<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no"><title>八、GC 性能优化 – GC 调优(实战篇) | 云少IT</title><meta name="keywords" content="JVM"><meta name="author" content="云少"><meta name="copyright" content="云少"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="mobile-web-app-capable" content="yes"><meta name="apple-touch-fullscreen" content="yes"><meta name="apple-mobile-web-app-title" content="八、GC 性能优化 – GC 调优(实战篇)"><meta name="application-name" content="八、GC 性能优化 – GC 调优(实战篇)"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="#ffffff"><meta property="og:type" content="article"><meta property="og:title" content="八、GC 性能优化 – GC 调优(实战篇)"><meta property="og:url" content="https://it985.github.io/posts/727d80c8.html"><meta property="og:site_name" content="云少IT"><meta property="og:description" content="八、GC 性能优化 – GC 调优(实战篇) master ，这是我的小站,欢迎访问哦~~  本章介绍导致GC性能问题的典型情况。相关示例都来源于生产环境, 为演示需要做了一定程度的精简。 说明: Allocation Rate, 翻译为分配速率, 而不是分配率; 因为不是百分比,而是单位时间内分配"><meta property="og:locale" content="zh-CN"><meta property="og:image" content="https://cn.bing.com/th?id=OHR.MarigoldsLosMuertos_EN-US5597948262_UHD.jpg"><meta property="article:author" content="云少"><meta property="article:tag" content="云少IT,IT,技术,分享,程序员,博客,教程,工具,框架,bug,java,spring,数据库,"><meta name="twitter:card" content="summary"><meta name="twitter:image" content="https://cn.bing.com/th?id=OHR.MarigoldsLosMuertos_EN-US5597948262_UHD.jpg"><meta name="description" content="八、GC 性能优化 – GC 调优(实战篇) master ，这是我的小站,欢迎访问哦~~  本章介绍导致GC性能问题的典型情况。相关示例都来源于生产环境, 为演示需要做了一定程度的精简。 说明: Allocation Rate, 翻译为分配速率, 而不是分配率; 因为不是百分比,而是单位时间内分配"><link rel="shortcut icon" href="/img/logo.webp"><link rel="canonical" href="https://it985.github.io/posts/727d80c8"><link rel="preconnect" href="//npm.elemecdn.com"><link rel="preconnect" href="//npm.onmicrosoft.cn"><link rel="preconnect" href="//www.google-analytics.com" crossorigin=""><link rel="preconnect" href="//busuanzi.ibruce.info"><meta name="google-site-verification" content="NuBZ4r-QCqSgo4XUScdEsQW0bolIHEiVGq4A16ndPQA"><meta name="baidu-site-verification" content="code-xxx"><meta name="msvalidate.01" content="xxx"><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.cbd.int/@fortawesome/fontawesome-free@6.4.0/css/all.min.css" media="print" onload='this.media="all"'><link rel="stylesheet" href="https://cdn.cbd.int/node-snackbar@0.1.16/dist/snackbar.min.css" media="print" onload='this.media="all"'><link rel="stylesheet" href="https://cdn.cbd.int/@fancyapps/ui@5.0.20/dist/fancybox/fancybox.css" media="print" onload='this.media="all"'><link rel="stylesheet" href="https://npm.elemecdn.com/anzhiyu-theme-static@1.0.0/swiper/swiper.min.css" media="print" onload='this.media="all"'><script async src="https://www.googletagmanager.com/gtag/js?id=G-3VMKW5TZBM"></script><script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-3VMKW5TZBM")</script><script>const GLOBAL_CONFIG={linkPageTop:{enable:!0,title:"与数百名博主无限进步",addFriendPlaceholder:"昵称（请勿包含博客等字样）：\n网站地址（要求博客地址，请勿提交个人主页）：\n头像图片url（请提供尽可能清晰的图片，我会上传到我自己的图床）：\n描述：\n站点截图（可选）：\n"},peoplecanvas:void 0,postHeadAiDescription:{enable:!0,gptName:"云AI",mode:"tianli",switchBtn:!1,btnLink:"https://afdian.net/item/886a79d4db6711eda42a52540025c377",randomNum:3,basicWordCount:1e3,key:"48580d1e3f53ae174a1e",Referer:"https://blog.tryrun.top"},diytitle:{enable:!0,leaveTitle:"w(ﾟДﾟ)w 不要走！再看看嘛！",backTitle:"♪(^∇^*)欢迎肥来！"},LA51:{enable:!0,ck:"JiFOrFoQklEn9YLS",LingQueMonitorID:"JiqlTmdeI4e1fPbd"},greetingBox:{enable:!0,default:"晚上好👋",list:[{greeting:"晚安😴",startTime:0,endTime:5},{greeting:"早上好鸭👋, 祝你一天好心情！",startTime:6,endTime:9},{greeting:"上午好👋, 状态很好，鼓励一下～",startTime:10,endTime:10},{greeting:"11点多啦, 在坚持一下就吃饭啦～",startTime:11,endTime:11},{greeting:"午安👋, 宝贝",startTime:12,endTime:14},{greeting:"🌈充实的一天辛苦啦！",startTime:14,endTime:18},{greeting:"19点喽, 奖励一顿丰盛的大餐吧🍔。",startTime:19,endTime:19},{greeting:"晚上好👋, 在属于自己的时间好好放松😌~",startTime:20,endTime:24}]},twikooEnvId:"https://twikoo.tryrun.top/",commentBarrageConfig:void 0,root:"/",preloader:{source:2},friends_vue_info:{apiurl:"https://friends.tryrun.top/"},navMusic:!1,mainTone:void 0,authorStatus:{skills:["🤖️ 数码科技爱好者","🔍 分享与热心帮助","🏠 智能家居小能手","🔨 设计开发一条龙","🤝 专修交互与设计","🏃 脚踏实地行动派","🧱 团队小组发动机","💢 壮汉人狠话不多"]},algolia:{appId:"T5VW6VDYLS",apiKey:"227bcb041816af13cb1698db15a8ac89",indexName:"hexo-blog",hits:{per_page:6},languages:{input_placeholder:"输入关键词后按下回车查找",hits_empty:"找不到您查询的内容：${query}",hits_stats:"找到 ${hits} 条结果，用时 ${time} 毫秒"}},localSearch:void 0,translate:{defaultEncoding:2,translateDelay:0,msgToTraditionalChinese:"繁",msgToSimplifiedChinese:"简",rightMenuMsgToTraditionalChinese:"转为繁体",rightMenuMsgToSimplifiedChinese:"转为简体"},noticeOutdate:{limitDay:365,position:"top",messagePrev:"It has been",messageNext:"days since the last update, the content of the article may be outdated."},highlight:{plugin:"highlighjs",highlightCopy:!0,highlightLang:!0,highlightHeightLimit:330},copy:{success:"复制成功",error:"复制错误",noSupport:"浏览器不支持"},relativeDate:{homepage:!0,simplehomepage:!1,post:!0},runtime:"天",date_suffix:{just:"刚刚",min:"分钟前",hour:"小时前",day:"天前",month:"个月前"},copyright:void 0,lightbox:"fancybox",Snackbar:{chs_to_cht:"你已切换为繁体",cht_to_chs:"你已切换为简体",day_to_night:"你已切换为深色模式",night_to_day:"你已切换为浅色模式",bgLight:"#425AEF",bgDark:"#1f1f1f",position:"top-center"},source:{justifiedGallery:{js:"https://cdn.cbd.int/flickr-justified-gallery@2.1.2/dist/fjGallery.min.js",css:"https://cdn.cbd.int/flickr-justified-gallery@2.1.2/dist/fjGallery.css"}},isPhotoFigcaption:!1,islazyload:!0,isAnchor:!1,shortcutKey:void 0,autoDarkmode:!0}</script><script id="config-diff">var GLOBAL_CONFIG_SITE={configTitle:"云少IT",title:"八、GC 性能优化 – GC 调优(实战篇)",postAI:"true - 优化",pageFillDescription:"八、GC 性能优化 – GC 调优(实战篇), 高分配速率(High Allocation Rate), 如何测量分配速率?, 分配速率的意义, 示例, 高分配速率对JVM的影响, 解决方案, 过早提升(Premature Promotion), 如何测量提升速率, 提升速率的意义, 示例, 过早提升的影响, 解决方案, Weak Soft 及 Phantom 引用, 弱引用的缺点, 示例, 使用非强引用的影响, 解决方案, 其他示例, RMI 与 GC, JVMTI tagging 与 GC, 巨无霸对象的分配(Humongous Allocations), 总结八性能优化调优实战篇这是我的小站欢迎访问哦本章介绍导致性能问题的典型情况相关示例都来源于生产环境为演示需要做了一定程度的精简说明翻译为分配速率而不是分配率因为不是百分比而是单位时间内分配的量同理翻译为提升速率您应该已经阅读了前面的章节高分配速率分配速率表示单位时间内分配的内存量通常使用作为单位也可以使用等分配速率过高就会严重影响程序的性能在中会导致巨大的开销如何测量分配速率指定参数通过日志来计算分配速率日志如下所示计算上一次垃圾收集之后与下一次开始之前的年轻代使用量两者的差值除以时间就是分配速率通过上面的日志可以计算出以下信息启动之后共创建了的对象第一次小型完成后年轻代中还有的对象存活在启动之后年轻代的使用量增加到触发第二次完成后年轻代的使用量减少到在启动之后年轻代的使用量为后变为可以通过年轻代的使用量来计算分配速率如下表所示通过这些信息可以知道在测量期间该程序的内存分配速率为分配速率的意义分配速率的变化会增加或降低暂停的频率从而影响吞吐量但只有年轻代的受分配速率的影响老年代的频率和持续时间不受分配速率的直接影响而是受到提升速率的影响请参见下文现在我们只关心暂停查看年轻代的个内存池因为对象在区分配所以我们一起来看区的大小和分配速率的关系看看增加区的容量能不能减少暂停次数从而使程序能够维持更高的分配速率经过我们的实验通过参数以及设置不同的空间运行同一程序时可以发现空间为时分配速率低于秒将区增大为分配速率也随之增长大约等于秒为什么会这样因为减少暂停就等价于减少了任务线程的停顿就可以做更多工作也就创建了更多对象所以对同一应用来说分配速率越高越好在得出区越大越好这个结论前我们注意到分配速率可能会也可能不会影响程序的实际吞吐量吞吐量和分配速率有一定关系因为分配速率会影响暂停但对于总体吞吐量的影响还要考虑大型暂停而且吞吐量的单位不是秒而是系统所处理的业务量示例参考程序假设系统连接了一个外部的数字传感器应用通过专有线程不断地获取传感器的值此处使用随机数模拟其他线程会调用方法传入传感器的值来执行某些操作如同类名所示这个是模拟的为了值判断使用的是包装类型程序基于传感器的最新值进行计算但从传感器取值是一个重量级操作所以采用了异步方式一个线程不断获取新值计算线程则直接使用暂存的最新值从而避免同步等待程序在运行的过程中由于分配速率太大而受到的影响下一节将确认问题并给出解决办法高分配速率对的影响首先我们应该检查程序的吞吐量是否降低如果创建了过多的临时对象的次数就会增加如果并发较大则可能会严重影响吞吐量遇到这种情况时日志将会像下面这样当然这是上面的示例程序产生的日志启动参数为很显然的频率太高了这说明创建了大量的对象另外年轻代在之后的使用量又很低也没有发生种种迹象表明对吞吐量造成了严重的影响解决方案在某些情况下只要增加年轻代的大小即可降低分配速率过高所造成的影响增加年轻代空间并不会降低分配速率但是会减少的频率如果每次后只有少量对象存活的暂停时间就不会明显增加运行示例程序时增加堆内存大小同时也就增大了年轻代的大小使用的参数为但有时候增加堆内存的大小并不能解决问题通过前面学到的知识我们可以通过分配分析器找出大部分垃圾产生的位置实际上在此示例中的对象属于包装类在方法中创建最简单的优化将创建的对象替换为原生类型而针对值的检测可以使用来进行由于原生类型不算是对象也就不会产生垃圾导致事件优化之后不在堆中分配新对象而是直接覆盖一个属性域即可对示例程序进行简单的改造查看后暂停基本上完全消除有时候也很智能会使用逃逸分析技术来避免过度分配简单来说编译器可以通过分析得知方法创建的某些对象永远都不会逃出此方法的作用域这时候就不需要在堆上分配这些对象也就不会产生垃圾所以编译器的一种优化手段就是消除内存分配请参考基准测试过早提升提升速率用于衡量单位时间内从年轻代提升到老年代的数据量一般使用作为单位和分配速率类似会将长时间存活的对象从年轻代提升到老年代根据分代假设可能存在一种情况老年代中不仅有存活时间长的对象也可能有存活时间短的对象这就是过早提升对象存活时间还不够长的时候就被提升到了老年代不是为频繁回收而设计的但现在也要清理这些生命短暂的对象就会导致暂停时间过长这会严重影响系统的吞吐量如何测量提升速率可以指定参数通过日志来测量提升速率记录的暂停信息如下所示从上面的日志可以得知之前和之后的年轻代使用量以及堆内存使用量这样就可以通过差值算出老年代的使用量日志中的信息可以表述为事件耗时年轻代减少整个堆内存减少提升量提升速率根据这些信息就可以计算出观测周期内的提升速率平均提升速率为秒峰值为秒请注意只能根据计算提升速率的日志不能用于计算提升速率因为会清理掉老年代中的一部分对象提升速率的意义和分配速率一样提升速率也会影响暂停的频率但分配速率主要影响而提升速率则影响的频率有大量的对象提升自然很快将老年代填满老年代填充的越快则事件的频率就会越高此前说过通常需要更多的时间因为需要处理更多的对象还要执行碎片整理等额外的复杂过程示例让我们看一个过早提升的示例这个程序创建获取大量的对象数据并暂存到集合之中达到一定数量后进行批处理此程序受到过早提升的影响下文将进行验证并给出解决办法过早提升的影响一般来说过早提升的症状表现为以下形式短时间内频繁地执行每次后老年代的使用率都很低在或以下提升速率接近于分配速率要演示这种情况稍微有点麻烦所以我们使用特殊手段让对象提升到老年代的年龄比默认情况小很多指定参数运行程序之后可以看到下面的日志乍一看似乎不是过早提升的问题事实上在每次之后老年代的使用率似乎在减少但反过来想要是没有对象提升或者提升率很小也就不会看到这么多的了简单解释一下这里的行为有很多对象提升到老年代同时老年代中也有很多对象被回收了这就造成了老年代使用量减少的假象但事实是大量的对象不断地被提升到老年代并触发解决方案简单来说要解决这类问题需要让年轻代存放得下暂存的数据有两种简单的方法一是增加年轻代的大小设置启动参数类似这样程序在执行时的次数自然会减少很多只会对的持续时间产生影响二是减少每次批处理的数量也能得到类似的结果至于选用哪个方案要根据业务需求决定在某些情况下业务逻辑不允许减少批处理的数量那就只能增加堆内存或者重新指定年轻代的大小如果都不可行就只能优化数据结构减少内存消耗但总体目标依然是一致的让临时数据能够在年轻代存放得下及引用另一类影响的问题是程序中的引用虽然这类引用在很多情况下可以避免出现但过量使用也会对造成严重的影响反而降低系统性能弱引用的缺点首先弱引用是可以被强制回收的当垃圾收集器发现一个弱可达对象即指向该对象的引用只剩下弱引用时就会将其置入相应的中变成可终结的对象之后可能会遍历这个并执行相应的清理典型的示例是清除缓存中不再引用的当然在这个时候我们还可以将该对象赋值给新的强引用在最后终结和回收前会再次确认该对象是否可以安全回收因此弱引用对象的回收过程是横跨多个周期的实际上弱引用使用的很多大部分缓存框架都是基于弱引用实现的所以虽然业务代码中没有直接使用弱引用但程序中依然会大量存在其次软引用比弱引用更难被垃圾收集器回收回收软引用没有确切的时间点由自己决定一般只会在即将耗尽可用内存时才会回收软引用以作最后手段这意味着可能会有更频繁的暂停时间也比预期更长因为老年代中的存活对象会很多最后使用虚引用时必须手动进行内存管理以标识这些对象是否可以安全地回收表面上看起来很正常但实际上并不是这样中写道为了防止可回收对象的残留虚引用对象不应该被获取的方法返回值永远是令人惊讶的是很多开发者忽略了下一段内容这才是重点与软引用和弱引用不同虚引用不会被自动清除因为他们被存放到队列中通过虚引用可达的对象会继续留在内存中直到调用此引用的方法或者引用自身变为不可达也就是说我们必须手动调用来清除虚引用否则可能会造成而导致挂掉使用虚引用的理由是对于用编程手段来跟踪某个对象何时变为不可达对象这是唯一的常规手段和软引用弱引用不同的是我们不能复活虚可达对象示例让我们看一个弱引用示例其中创建了大量的对象并在中完成回收和前面一样修改提升阀值使用的参数为日志如下所示可以看到的次数很少但如果使用弱引用来指向创建的对象使用参数则情况会发生明显变化使用弱引用的原因很多比如在中将对象作为的情况在任何情况下使用弱引用都可能会导致以下情形可以看到发生了多次比起前一节的示例时间增加了一个数量级这是过早提升的另一个例子但这次情况更加棘手当然问题的根源在于弱引用这些临死的对象在添加弱引用之后被提升到了老年代但是他们现在陷入另一次循环之中所以需要对其做一些适当的清理像之前一样最简单的办法是增加年轻代的大小例如指定参数这时候对象在中就被回收了更坏的情况是使用软引用例如这个软引用示例程序如果程序不是即将发生软引用对象就不会被回收在示例程序中用软引用替代弱引用立即出现了更多的事件最有趣的是虚引用示例中的虚引用使用同样的参数启动其结果和弱引用示例非常相似实际上暂停的次数会小得多原因前面说过他们有不同的终结方式如果禁用虚引用清理增加启动参数则可以看到线程中抛出异常使用虚引用时要小心谨慎并及时清理虚可达对象如果不清理很可能会发生请相信我们的经验教训处理的线程中如果没住系统很快就会被整挂了使用非强引用的影响建议使用参数来看看各种引用对的影响如果将此参数用于启动弱引用示例将会看到只有确定对应用的吞吐量和延迟造成影响之后才应该花心思来分析这些信息审查这部分日志通常情况下每次清理的引用数量都是很少的大部分情况下为如果花了较多时间来清理这类引用或者清除了很多的此类引用就需要进一步观察和分析了解决方案如果程序确实碰到了问题或者滥用引用一般都要修改程序的实现逻辑每个系统不一样因此很难提供通用的指导建议但有一些常用的办法弱引用如果某个内存池的使用量增大造成了性能问题那么增加这个内存池的大小可能也要增加堆内存的最大容量如同示例中所看到的增加堆内存的大小以及年轻代的大小可以减轻症状虚引用请确保在程序中调用了虚引用的方法编程中很容易忽略某些虚引用或者清理的速度跟不上生产的速度又或者清除引用队列的线程挂了就会对造成很大压力最终可能引起软引用如果确定问题的根源是软引用唯一的解决办法是修改程序源码改变内部实现逻辑其他示例前面介绍了最常见的性能问题但我们学到的很多原理都没有具体的场景来展现本节介绍一些不常发生但也可能会碰到的问题与如果系统提供或者消费服务则会定期执行来确保本地未使用的对象在另一端也不占用空间记住即使你的代码中没有发布服务但第三方或者工具库也可能会打开终端最常见的元凶是如果通过连接到远端底层则会使用发布数据问题是有很多不必要的周期性查看老年代的使用情况一般是没有内存压力其中还存在大量的空闲区域但就是被触发了也就会暂停所有的应用线程这种周期性调用删除远程引用的行为是在类中通过调用的对许多应用来说根本没必要甚至对性能有害禁止这种周期性的行为可以使用以下参数这让毫秒之后才调用实际运行的系统可能永远都不会触发可以看到默认值为也就是小时触发一次另一种方式是指定参数禁止显式地调用但我们强烈反对这种方式因为埋有地雷与如果在程序启动时指定了就可以使用标记堆中的对象使用的种种原因本手册不详细讲解但如果标记了大量的对象很可能会引起性能问题导致延迟增加以及吞吐量降低问题发生在代码中在每次时都会遍历所有标签并执行一些比较耗时的操作更坑的是这种操作是串行执行的如果存在大量的标签就意味着时有很大一部分工作是单线程执行的暂停时间可能会增加一个数量级检查是否因为增加了暂停时间可以使用诊断参数启用跟踪之后可以估算出内存中映射了多少内存以及遍历所消耗的时间如果你不是的作者那一般是搞不定这类问题的除了提之外你什么都做不了如果发生了这种情况请建议厂商清理不必要的标签巨无霸对象的分配如果使用垃圾收集算法会产生一种巨无霸对象引起的性能问题说明在中巨无霸对象是指所占空间超过一个小堆区的对象频繁的创建巨无霸对象无疑会造成的性能问题看看的处理方式如果某个中含有巨无霸对象则巨无霸对象后面的空间将不会被分配如果所有巨无霸对象都超过某个比例则未使用的空间就会引发内存碎片问题没有对巨无霸对象进行优化这在以前是个特别棘手的问题在之前的版本中巨无霸对象所在的回收只能在中进行最新版本的在阶段之后的阶段中释放巨无霸区间所以这个问题在新版本中的影响已大大降低要监控是否存在巨无霸对象可以打开日志使用的命令如下日志中可能会发现这样的部分这样的日志就是证据表明程序中确实创建了巨无霸对象可以看到是暂停的原因再看前面一点的可以发现程序试图分配一个字节的对象这要比巨无霸区域的多出个字节第一种解决方式是修改以使得大多数的对象不超过也就不进行巨无霸对象区域的分配的默认大小在启动时根据堆内存的大小算出但也可以指定参数来覆盖默认设置指定的必须在之间还必须是的幂所以只能是这种方式也有副作用增加的大小也就变相地减少了的数量所以需要谨慎使用最好进行一些测试看看是否改善了吞吐量和延迟更好的方式需要一些工作量如果可以的话在程序中限制对象的大小最好是使用分析器展示出巨无霸对象的信息以及分配时所在的堆栈跟踪信息总结上运行的程序多种多样启动参数也有上百个其中有很多会影响到所以调优性能的方法也有很多种还是那句话没有真正的银弹能满足所有的性能调优指标我们能做的只是介绍一些常见的和不常见的示例让你在碰到类似问题时知道是怎么回事深入理解的工作原理熟练应用各种工具就可以进行调优提高程序性能",isPost:!0,isHome:!1,isHighlightShrink:!0,isToc:!0,postUpdate:"2022-05-18 18:53:58",postMainColor:""}</script><noscript><style>#nav{opacity:1}.justified-gallery img{opacity:1}#post-meta time,#recent-posts time{display:inline!important}</style></noscript><script>(e=>{e.saveToLocal={set:(e,t,a)=>{var o;0!==a&&(o=Date.now(),localStorage.setItem(e,JSON.stringify({value:t,expiry:o+864e5*a})))},get:e=>{var t=localStorage.getItem(e);if(t){t=JSON.parse(t);if(!(Date.now()>t.expiry))return t.value;localStorage.removeItem(e)}}},e.getScript=(o,c={})=>new Promise((t,e)=>{const a=document.createElement("script");a.src=o,a.async=!0,a.onerror=e,a.onload=a.onreadystatechange=function(){var e=this.readyState;e&&"loaded"!==e&&"complete"!==e||(a.onload=a.onreadystatechange=null,t())},Object.keys(c).forEach(e=>{a.setAttribute(e,c[e])}),document.head.appendChild(a)}),e.getCSS=(o,c=!1)=>new Promise((t,e)=>{const a=document.createElement("link");a.rel="stylesheet",a.href=o,c&&(a.id=c),a.onerror=e,a.onload=a.onreadystatechange=function(){var e=this.readyState;e&&"loaded"!==e&&"complete"!==e||(a.onload=a.onreadystatechange=null,t())},document.head.appendChild(a)}),e.activateDarkMode=()=>{document.documentElement.setAttribute("data-theme","dark"),null!==document.querySelector('meta[name="theme-color"]')&&document.querySelector('meta[name="theme-color"]').setAttribute("content","#0d0d0d")},e.activateLightMode=()=>{document.documentElement.setAttribute("data-theme","light"),null!==document.querySelector('meta[name="theme-color"]')&&document.querySelector('meta[name="theme-color"]').setAttribute("content","#ffffff")};var e=saveToLocal.get("theme"),t=window.matchMedia("(prefers-color-scheme: dark)").matches,a=window.matchMedia("(prefers-color-scheme: light)").matches,o=window.matchMedia("(prefers-color-scheme: no-preference)").matches,c=!t&&!a&&!o,t=(void 0===e?(a?activateLightMode():t?activateDarkMode():(o||c)&&((a=(new Date).getHours())<=6||18<=a?activateDarkMode:activateLightMode)(),window.matchMedia("(prefers-color-scheme: dark)").addListener(e=>{void 0===saveToLocal.get("theme")&&(e.matches?activateDarkMode:activateLightMode)()})):("light"===e?activateLightMode:activateDarkMode)(),saveToLocal.get("aside-status"));void 0!==t&&("hide"===t?document.documentElement.classList.add("hide-aside"):document.documentElement.classList.remove("hide-aside"));/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)&&document.documentElement.classList.add("apple")})(window)</script><link rel="stylesheet" href="/css/1.min.css?1" media="async" onload='this.media="all"'><link rel="stylesheet" href="/css/bg.css?1" media="async" onload='this.media="all"'><meta name="generator" content="Hexo 6.3.0"><link rel="alternate" href="/atom.xml" title="云少IT" type="application/atom+xml"><link rel="alternate" href="/rss.xml" title="云少IT" type="application/rss+xml"></head><body data-type="anzhiyu"><div id="web_bg"></div><div id="an_music_bg"></div><link rel="stylesheet" href="https://cdn.cbd.int/anzhiyu-theme-static@1.1.10/progress_bar/progress_bar.css"><script async src="https://cdn.cbd.int/pace-js@1.2.4/pace.min.js" data-pace-options="{ &quot;restartOnRequestAfter&quot;:false,&quot;eventLag&quot;:false}"></script><div class="post" id="body-wrap"><header class="post-bg" id="page-header"><nav id="nav"><div id="nav-group"><span id="blog_name"><div class="back-home-button"><i class="anzhiyufont anzhiyu-icon-grip-vertical"></i><div class="back-menu-list-groups"><div class="back-menu-list-group"><div class="back-menu-list-title">网页</div><div class="back-menu-list"><a class="back-menu-item" target="_blank" rel="noopener external nofollow noreferrer" href="https://www.tryrun.top/" title="博客"><img class="back-menu-item-icon" src="/img/favicon.ico" alt="博客"><span class="back-menu-item-text">博客</span></a></div></div><div class="back-menu-list-group"><div class="back-menu-list-title">项目</div><div class="back-menu-list"><a class="back-menu-item" target="_blank" rel="noopener external nofollow noreferrer" href="https://www.tryrun.top" title="图床"><img class="back-menu-item-icon" src="https://www.tryrun.top/favicon.ico" alt="图床"><span class="back-menu-item-text">图床</span></a></div></div></div></div><a id="site-name" href="/" accesskey="h"><div class="title">云少IT</div><i class="anzhiyufont anzhiyu-icon-house-chimney"></i></a></span><div class="mask-name-container"><div id="name-container"><a id="page-name" href="javascript:anzhiyu.scrollToDest(0, 500)" rel="external nofollow noreferrer">PAGE_NAME</a></div></div><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="javascript:void(0);" rel="external nofollow noreferrer"><span>望四方</span></a><ul class="menus_item_child"><li><a class="site-page child faa-parent animated-hover" href="/archives/"><i class="anzhiyufont anzhiyu-icon-box-archive faa-tada" style="font-size:.9em"></i><span> 归名档</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/categories/"><i class="anzhiyufont anzhiyu-icon-shapes faa-tada" style="font-size:.9em"></i><span> 归四类</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/tags/"><i class="anzhiyufont anzhiyu-icon-tags faa-tada" style="font-size:.9em"></i><span> 书中签</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/charts/"><i class="fa-fw fas fa-chart-bar faa-tada"></i><span> 统计</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="javascript:void(0);" rel="external nofollow noreferrer"><span>友链</span></a><ul class="menus_item_child"><li><a class="site-page child faa-parent animated-hover" href="/link/"><i class="anzhiyufont anzhiyu-icon-link faa-tada" style="font-size:.9em"></i><span> 四方好友</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/fcircle/"><i class="anzhiyufont anzhiyu-icon-artstation faa-tada" style="font-size:.9em"></i><span> 朋友圈</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/comments/"><i class="anzhiyufont anzhiyu-icon-envelope faa-tada" style="font-size:.9em"></i><span> 留言板</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="javascript:void(0);" rel="external nofollow noreferrer"><span>我的</span></a><ul class="menus_item_child"><li><a class="site-page child faa-parent animated-hover" href="/bangumis/"><i class="anzhiyufont anzhiyu-icon-bilibili faa-tada" style="font-size:.9em"></i><span> 追番页</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/album/"><i class="anzhiyufont anzhiyu-icon-images faa-tada" style="font-size:.9em"></i><span> 刹那间</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/equipment/"><i class="fas fa-heart faa-tada"></i><span> 我的装备</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/collect/"><i class="fas fa-camcorder faa-tada"></i><span> 观影阁</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="javascript:void(0);" rel="external nofollow noreferrer"><span>关于</span></a><ul class="menus_item_child"><li><a class="site-page child faa-parent animated-hover" href="/about/"><i class="anzhiyufont anzhiyu-icon-paper-plane faa-tada" style="font-size:.9em"></i><span> 关于本人</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/essay/"><i class="anzhiyufont anzhiyu-icon-lightbulb faa-tada" style="font-size:.9em"></i><span> 闲言碎语</span></a></li><li><a class="site-page child faa-parent animated-hover" href="javascript:toRandomPost()" rel="external nofollow noreferrer"><i class="anzhiyufont anzhiyu-icon-shoe-prints1 faa-tada" style="font-size:.9em"></i><span> 随便逛逛</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/disclaimer/"><i class="fas fa-heart faa-tada"></i><span> 免责声明</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/love/"><i class="anzhiyufont anzhiyu-icon-heartbeat faa-tada" style="font-size:.9em"></i><span> 恋爱小屋</span></a></li></ul></div></div></div><div id="nav-right"><div class="nav-button only-home" id="travellings_button" title="随机前往一个开往项目网站"><a class="site-page" onclick="anzhiyu.totraveling()" title="随机前往一个开往项目网站" href="javascript:void(0);" rel="external nofollow" data-pjax-state="external"><i class="anzhiyufont anzhiyu-icon-train"></i></a></div><div class="nav-button" id="randomPost_button"><a class="site-page" onclick="toRandomPost()" title="随机前往一个文章" href="javascript:void(0);" rel="external nofollow noreferrer"><i class="anzhiyufont anzhiyu-icon-dice"></i></a></div><div class="nav-button" id="search-button"><a class="site-page social-icon search" href="javascript:void(0);" rel="external nofollow noreferrer" title="搜索🔍" accesskey="s"><i class="anzhiyufont anzhiyu-icon-magnifying-glass"></i><span> 搜索</span></a></div><input id="center-console" type="checkbox"><label class="widget" for="center-console" title="中控台" onclick="anzhiyu.switchConsole()"><i class="left"></i><i class="widget center"></i><i class="widget right"></i></label><div id="console"><div class="console-card-group-reward"><ul class="reward-all console-card"><li class="reward-item"><a href="/img/wxpay.webp" target="_blank"><img class="post-qr-code-img" alt="wechat" src="/img/wxpay.webp"></a><div class="post-qr-code-desc">wechat</div></li><li class="reward-item"><a href="/img/alipay.webp" target="_blank"><img class="post-qr-code-img" alt="alipay" src="/img/alipay.webp"></a><div class="post-qr-code-desc">alipay</div></li></ul></div><div class="console-card-group"><div class="console-card-group-left"><div class="console-card" id="card-newest-comments"><div class="card-content"><div class="author-content-item-tips">互动</div><span class="author-content-item-title">最新评论</span></div><div class="aside-list"><span>正在加载中...</span></div></div></div><div class="console-card-group-right"><div class="console-card tags"><div class="card-content"><div class="author-content-item-tips">兴趣点</div><span class="author-content-item-title">寻找你感兴趣的领域</span><div class="card-tags"><div class="item-headline"></div><div class="card-tag-cloud"><a href="/tags/API/" style="font-size:1.05rem;color:#637571">API<sup>43</sup></a><a href="/tags/Base64/" style="font-size:1.05rem;color:#8a0460">Base64<sup>1</sup></a><a href="/tags/Collectors/" style="font-size:1.05rem;color:#6b3641">Collectors<sup>3</sup></a><a href="/tags/Date/" style="font-size:1.05rem;color:#5e6603">Date<sup>3</sup></a><a href="/tags/Executor/" style="font-size:1.05rem;color:#abb61f">Executor<sup>9</sup></a><a href="/tags/Guava/" style="font-size:1.05rem;color:#6dc55c">Guava<sup>1</sup></a><a href="/tags/JVM/" style="font-size:1.05rem;color:#8745c2">JVM<sup>8</sup></a><a href="/tags/Java8/" style="font-size:1.05rem;color:#804042">Java8<sup>21</sup></a><a href="/tags/Java9/" style="font-size:1.05rem;color:#21b4c6">Java9<sup>21</sup></a><a href="/tags/Java%E5%B9%B6%E5%8F%91/" style="font-size:1.05rem;color:#0a3988">Java并发<sup>20</sup></a><a href="/tags/Lambda/" style="font-size:1.05rem;color:#29446d">Lambda<sup>4</sup></a><a href="/tags/Lock/" style="font-size:1.05rem;color:#afc378">Lock<sup>1</sup></a><a href="/tags/Maven/" style="font-size:1.05rem;color:#b10843">Maven<sup>1</sup></a><a href="/tags/Memcached/" style="font-size:1.05rem;color:#9663a4">Memcached<sup>23</sup></a><a href="/tags/Mongodb/" style="font-size:1.05rem;color:#b4214d">Mongodb<sup>49</sup></a><a href="/tags/Queue/" style="font-size:1.05rem;color:#220f01">Queue<sup>1</sup></a><a href="/tags/Redis/" style="font-size:1.05rem;color:#c4106c">Redis<sup>27</sup></a><a href="/tags/Stream/" style="font-size:1.05rem;color:#1f5f9f">Stream<sup>4</sup></a><a href="/tags/Thread/" style="font-size:1.05rem;color:#c3563b">Thread<sup>7</sup></a><a href="/tags/Thread-pool/" style="font-size:1.05rem;color:#1a3364">Thread pool<sup>7</sup></a><a href="/tags/forkJoinPool/" style="font-size:1.05rem;color:#1ea132">forkJoinPool<sup>2</sup></a><a href="/tags/stream/" style="font-size:1.05rem;color:#a00679">stream<sup>1</sup></a><a href="/tags/%E4%B8%93%E6%A0%8F/" style="font-size:1.05rem;color:#9e5e9b">专栏<sup>35</sup></a><a href="/tags/%E4%BA%8B%E5%8A%A1/" style="font-size:1.05rem;color:#4d47bc">事务<sup>1</sup></a><a href="/tags/%E4%BC%98%E5%8C%96/" style="font-size:1.05rem;color:#a56245">优化<sup>1</sup></a><a href="/tags/%E5%91%BD%E4%BB%A4/" style="font-size:1.05rem;color:#9c8435">命令<sup>57</sup></a><a href="/tags/%E5%AE%89%E8%A3%85/" style="font-size:1.05rem;color:#647e28">安装<sup>6</sup></a><a href="/tags/%E5%B7%A5%E5%85%B7/" style="font-size:1.05rem;color:#a192b9">工具<sup>2</sup></a><a href="/tags/%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/" style="font-size:1.05rem;color:#22a370">数据类型<sup>8</sup></a><a href="/tags/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/" style="font-size:1.05rem;color:#6b985c">生命周期<sup>1</sup></a><a href="/tags/%E7%AE%80%E4%BB%8B/" style="font-size:1.05rem;color:#bc5f40">简介<sup>7</sup></a><a href="/tags/%E7%AE%97%E6%B3%95/" style="font-size:1.05rem;color:#167366">算法<sup>10</sup></a><a href="/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" style="font-size:1.05rem;color:#aa928f">设计模式<sup>38</sup></a><a href="/tags/%E9%85%8D%E7%BD%AE/" style="font-size:1.05rem;color:#3a740b">配置<sup>2</sup></a><a href="/tags/%E9%9D%A2%E8%AF%95/" style="font-size:1.05rem;color:#75c343">面试<sup>11</sup></a></div></div><hr></div></div><div class="console-card history"><div class="item-headline"><i class="anzhiyufont anzhiyu-icon-box-archiv"></i><span>文章</span></div><div class="card-archives"><div class="item-headline"><i class="anzhiyufont anzhiyu-icon-archive"></i><span>归档</span><a class="card-more-btn" href="/archives/" title="查看更多"> <i class="anzhiyufont anzhiyu-icon-angle-right"></i></a></div><ul class="card-archive-list"><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2023/06/"><span class="card-archive-list-date">六月 2023</span><div class="card-archive-list-count-group"><span class="card-archive-list-count">2</span><span>篇</span></div></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2021/05/"><span class="card-archive-list-date">五月 2021</span><div class="card-archive-list-count-group"><span class="card-archive-list-count">2</span><span>篇</span></div></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2020/10/"><span class="card-archive-list-date">十月 2020</span><div class="card-archive-list-count-group"><span class="card-archive-list-count">21</span><span>篇</span></div></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2020/09/"><span class="card-archive-list-date">九月 2020</span><div class="card-archive-list-count-group"><span class="card-archive-list-count">44</span><span>篇</span></div></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2020/08/"><span class="card-archive-list-date">八月 2020</span><div class="card-archive-list-count-group"><span class="card-archive-list-count">47</span><span>篇</span></div></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2020/07/"><span class="card-archive-list-date">七月 2020</span><div class="card-archive-list-count-group"><span class="card-archive-list-count">42</span><span>篇</span></div></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2020/06/"><span class="card-archive-list-date">六月 2020</span><div class="card-archive-list-count-group"><span class="card-archive-list-count">31</span><span>篇</span></div></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2020/05/"><span class="card-archive-list-date">五月 2020</span><div class="card-archive-list-count-group"><span class="card-archive-list-count">43</span><span>篇</span></div></a></li></ul></div><hr></div></div></div><div class="button-group"><div class="console-btn-item"><a class="darkmode_switchbutton" title="显示模式切换" href="javascript:void(0);" rel="external nofollow noreferrer"><i class="anzhiyufont anzhiyu-icon-moon"></i></a></div><div class="console-btn-item" id="consoleHideAside" onclick="anzhiyu.hideAsideBtn()" title="边栏显示控制"><a class="asideSwitch"><i class="anzhiyufont anzhiyu-icon-arrows-left-right"></i></a></div><div class="console-btn-item on" id="consoleCommentBarrage" onclick="anzhiyu.switchCommentBarrage()" title="热评开关"><a class="commentBarrage"><i class="anzhiyufont anzhiyu-icon-message"></i></a></div><div class="console-btn-item" id="consoleMusic" onclick="anzhiyu.musicToggle()" title="音乐开关"><a class="music-switch"><i class="anzhiyufont anzhiyu-icon-music"></i></a></div></div><div class="console-mask" onclick="anzhiyu.hideConsole()" href="javascript:void(0);" rel="external nofollow noreferrer"></div></div><div class="nav-button" id="nav-totop"><a class="totopbtn" href="javascript:void(0);" rel="external nofollow noreferrer"><i class="anzhiyufont anzhiyu-icon-arrow-up"></i><span id="percent" onclick="anzhiyu.scrollToDest(0,500)">0</span></a></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);" rel="external nofollow noreferrer" title="切换"><i class="anzhiyufont anzhiyu-icon-bars"></i></a></div></div></div></nav><div id="post-info"><div id="post-firstinfo"><div class="meta-firstline"><a class="post-meta-original">原创</a><span class="article-meta tags"><a class="article-meta__tags" href="/tags/JVM/" tabindex="-1" itemprop="url"> <span><i class="anzhiyufont anzhiyu-icon-hashtag"></i>JVM</span></a></span></div></div><h1 class="post-title" itemprop="name headline">八、GC 性能优化 – GC 调优(实战篇)</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="anzhiyufont anzhiyu-icon-calendar-days post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" itemprop="dateCreated datePublished" datetime="2019-01-31T11:12:48.000Z" title="发表于 2019-01-31 19:12:48">2019-01-31</time><span class="post-meta-separator"></span><i class="anzhiyufont anzhiyu-icon-history post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" itemprop="dateCreated datePublished" datetime="2022-05-18T10:53:58.000Z" title="更新于 2022-05-18 18:53:58">2022-05-18</time></span></div><div class="meta-secondline"><span class="post-meta-separator"></span><span class="post-meta-wordcount"><i class="anzhiyufont anzhiyu-icon-file-word post-meta-icon" title="文章字数"></i><span class="post-meta-label" title="文章字数">字数总计:</span><span class="word-count" title="文章字数">7.5k</span><span class="post-meta-separator"></span><i class="anzhiyufont anzhiyu-icon-clock post-meta-icon" title="阅读时长"></i><span class="post-meta-label" title="阅读时长">阅读时长:</span><span>28分钟</span></span><span class="post-meta-separator"></span><span class="post-meta-pv-cv" data-flag-title="八、GC 性能优化 – GC 调优(实战篇)"><i class="anzhiyufont anzhiyu-icon-fw-eye post-meta-icon"></i><span class="post-meta-label" title="阅读量">阅读量:</span><span id="busuanzi_value_page_pv"><i class="anzhiyufont anzhiyu-icon-spinner anzhiyu-spin"></i></span></span><span class="post-meta-separator"> </span><span class="post-meta-position" title="作者IP属地为武汉"><i class="anzhiyufont anzhiyu-icon-location-dot"></i>武汉</span></div></div></div><section class="main-hero-waves-area waves-area"><svg class="waves-svg" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" viewBox="0 24 150 28" preserveAspectRatio="none" shape-rendering="auto"><defs><path id="gentle-wave" d="M -160 44 c 30 0 58 -18 88 -18 s 58 18 88 18 s 58 -18 88 -18 s 58 18 88 18 v 44 h -352 Z"></path></defs><g class="parallax"><use href="#gentle-wave" x="48" y="0"></use><use href="#gentle-wave" x="48" y="3"></use><use href="#gentle-wave" x="48" y="5"></use><use href="#gentle-wave" x="48" y="7"></use></g></svg></section><div id="post-top-cover"><img class="nolazyload" id="post-top-bg" src="https://cn.bing.com/th?id=OHR.MoonJellyDay_EN-US5774626244_UHD.jpg"></div></header><main id="blog-container"><div class="layout" id="content-inner"><div id="post"><div class="post-ai-description"><div class="ai-title"><i class="anzhiyufont anzhiyu-icon-bilibili"></i><div class="ai-title-text">AI-摘要</div><i class="anzhiyufont anzhiyu-icon-arrow-rotate-right"></i><i class="anzhiyufont anzhiyu-icon-circle-dot" title="朗读摘要"></i><div id="ai-tag">Tianli GPT</div></div><div class="ai-explanation">AI初始化中...</div><div class="ai-btn-box"><div class="ai-btn-item">介绍自己 🙈</div><div class="ai-btn-item">生成本文简介 👋</div><div class="ai-btn-item">推荐相关文章 📖</div><div class="ai-btn-item">前往主页 🏠</div><div class="ai-btn-item" id="go-tianli-blog">前往爱发电购买</div></div><script data-pjax src="/js/anzhiyu/ai_abstract.js"></script></div><article class="post-content" id="article-container" itemscope itemtype="https://it985.github.io/posts/727d80c8.html"><header><a href="/tags/JVM/" tabindex="-1" itemprop="url">JVM</a><h1 id="CrawlerTitle" itemprop="name headline">八、GC 性能优化 – GC 调优(实战篇)</h1><span itemprop="author" itemscope itemtype="http://schema.org/Person">云少</span><time itemprop="dateCreated datePublished" datetime="2019-01-31T11:12:48.000Z" title="发表于 2019-01-31 19:12:48">2019-01-31</time><time itemprop="dateCreated datePublished" datetime="2022-05-18T10:53:58.000Z" title="更新于 2022-05-18 18:53:58">2022-05-18</time></header><h1 id="八、GC-性能优化-–-GC-调优-实战篇"><a href="#八、GC-性能优化-–-GC-调优-实战篇" class="headerlink" title="八、GC 性能优化 – GC 调优(实战篇)"></a>八、GC 性能优化 – GC 调优(实战篇)</h1><blockquote><p>master ，这是我的<a target="_blank" rel="noopener external nofollow noreferrer" href="https://www.tryrun.top/">小站</a>,欢迎访问哦~~</p></blockquote><p>本章介绍导致GC性能问题的典型情况。相关示例都来源于生产环境, 为演示需要做了一定程度的精简。</p><p><strong>说明</strong>: <code>Allocation Rate</code>, 翻译为<code>分配速率</code>, 而不是分配率; 因为不是百分比,而是单位时间内分配的量;</p><p>同理, <code>Promotion Rate</code> 翻译为 <code>提升速率</code>;</p><p>您应该已经阅读了前面的章节:</p><h2 id="高分配速率-High-Allocation-Rate"><a href="#高分配速率-High-Allocation-Rate" class="headerlink" title="高分配速率(High Allocation Rate)"></a>高分配速率(High Allocation Rate)</h2><p>分配速率(<code>Allocation rate</code>)表示单位时间内分配的内存量。通常使用 <code>MB/sec</code>作为单位, 也可以使用 <code>PB/year</code> 等。</p><p>分配速率过高就会严重影响程序的性能。在JVM中会导致巨大的GC开销。</p><h3 id="如何测量分配速率"><a href="#如何测量分配速率" class="headerlink" title="如何测量分配速率?"></a>如何测量分配速率?</h3><p>指定JVM参数: <code>-XX:+PrintGCDetails -XX:+PrintGCTimeStamps</code> , 通过GC日志来计算分配速率. GC日志如下所示:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">0.291: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 33280K-&gt;5088K(38400K)] </span><br><span class="line">        33280K-&gt;24360K(125952K), 0.0365286 secs] </span><br><span class="line">    [Times: user=0.11 sys=0.02, real=0.04 secs] </span><br><span class="line">0.446: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 38368K-&gt;5120K(71680K)] </span><br><span class="line">        57640K-&gt;46240K(159232K), 0.0456796 secs] </span><br><span class="line">    [Times: user=0.15 sys=0.02, real=0.04 secs] </span><br><span class="line">0.829: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 71680K-&gt;5120K(71680K)] </span><br><span class="line">        112800K-&gt;81912K(159232K), 0.0861795 secs] </span><br><span class="line">    [Times: user=0.23 sys=0.03, real=0.09 secs]</span><br></pre></td></tr></table></figure><p>计算 <code>上一次垃圾收集之后</code>,与<code>下一次GC开始之前</code>的年轻代使用量, 两者的差值除以时间,就是分配速率。 通过上面的日志, 可以计算出以下信息:</p><ul><li>JVM启动之后 <code>291ms</code>, 共创建了 <code>33,280 KB</code> 的对象。 第一次 Minor GC(小型GC) 完成后, 年轻代中还有 <code>5,088 KB</code> 的对象存活。</li><li>在启动之后 <code>446 ms</code>, 年轻代的使用量增加到 <code>38,368 KB</code>, 触发第二次GC, 完成后年轻代的使用量减少到 <code>5,120 KB</code>。</li><li>在启动之后 <code>829 ms</code>, 年轻代的使用量为 <code>71,680 KB</code>, GC后变为 <code>5,120 KB</code>。</li></ul><p>可以通过年轻代的使用量来计算分配速率, 如下表所示:</p><table><thead><tr><th align="center"><strong>Event</strong></th><th align="center"><strong>Time</strong></th><th align="center"><strong>Young before</strong></th><th align="center"><strong>Young after</strong></th><th align="center"><strong>Allocated during</strong></th><th align="center"><strong>Allocation rate</strong></th></tr></thead><tbody><tr><td align="center">1st GC</td><td align="center">291ms</td><td align="center">33,280KB</td><td align="center">5,088KB</td><td align="center">33,280KB</td><td align="center"><strong>114MB&#x2F;sec</strong></td></tr><tr><td align="center">2nd GC</td><td align="center">446ms</td><td align="center">38,368KB</td><td align="center">5,120KB</td><td align="center">33,280KB</td><td align="center"><strong>215MB&#x2F;sec</strong></td></tr><tr><td align="center">3rd GC</td><td align="center">829ms</td><td align="center">71,680KB</td><td align="center">5,120KB</td><td align="center">66,560KB</td><td align="center"><strong>174MB&#x2F;sec</strong></td></tr><tr><td align="center">Total</td><td align="center">829ms</td><td align="center">N&#x2F;A</td><td align="center">N&#x2F;A</td><td align="center">133,120KB</td><td align="center"><strong>161MB&#x2F;sec</strong></td></tr></tbody></table><p>通过这些信息可以知道, 在测量期间, 该程序的内存分配速率为 <code>161 MB/sec</code>。</p><h3 id="分配速率的意义"><a href="#分配速率的意义" class="headerlink" title="分配速率的意义"></a>分配速率的意义</h3><p>分配速率的变化,会增加或降低GC暂停的频率, 从而影响吞吐量。 但只有年轻代的 <a target="_blank" rel="noopener external nofollow noreferrer" href="http://blog.csdn.net/renfufei/article/details/54144385#t9">minor GC</a> 受分配速率的影响, 老年代GC的频率和持续时间不受 <strong>分配速率</strong>(<code>allocation rate</code>)的直接影响, 而是受到 <strong>提升速率</strong>(<code>promotion rate</code>)的影响, 请参见下文。</p><p>现在我们只关心 <a target="_blank" rel="noopener external nofollow noreferrer" href="http://blog.csdn.net/renfufei/article/details/54144385#t9">Minor GC</a> 暂停, 查看年轻代的3个内存池。因为对象在 <a target="_blank" rel="noopener external nofollow noreferrer" href="http://blog.csdn.net/renfufei/article/details/54144385#t3">Eden区</a>分配, 所以我们一起来看 Eden 区的大小和分配速率的关系. 看看增加 Eden 区的容量, 能不能减少 Minor GC 暂停次数, 从而使程序能够维持更高的分配速率。</p><p>经过我们的实验, 通过参数 <code>-XX:NewSize</code>、 <code>-XX:MaxNewSize</code> 以及 <code>-XX:SurvivorRatio</code> 设置不同的 Eden 空间, 运行同一程序时, 可以发现:</p><ul><li>Eden 空间为 <code>100 MB</code> 时, 分配速率低于 <code>100 MB/秒</code>。</li><li>将 Eden 区增大为 <code>1 GB</code>, 分配速率也随之增长,大约等于 <code>200 MB/秒</code>。</li></ul><p>为什么会这样? —— 因为减少GC暂停,就等价于减少了任务线程的停顿，就可以做更多工作, 也就创建了更多对象, 所以对同一应用来说, 分配速率越高越好。</p><p>在得出 “Eden区越大越好” 这个结论前, 我们注意到, 分配速率可能会,也可能不会影响程序的实际吞吐量。 吞吐量和分配速率有一定关系, 因为分配速率会影响 minor GC 暂停, 但对于总体吞吐量的影响, 还要考虑 Major GC(大型GC)暂停, 而且吞吐量的单位不是 <code>MB/秒</code>， 而是系统所处理的业务量。</p><h3 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h3><p>参考 <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/Boxing.java">Demo程序</a>。假设系统连接了一个外部的数字传感器。应用通过专有线程, 不断地获取传感器的值,(此处使用随机数模拟), 其他线程会调用 <code>processSensorValue()</code> 方法, 传入传感器的值来执行某些操作, :</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">public class BoxingFailure &#123;</span><br><span class="line">  private static volatile Double sensorValue;</span><br><span class="line"></span><br><span class="line">  private static void readSensor() &#123;</span><br><span class="line">    while(true) sensorValue = Math.random();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  private static void processSensorValue(Double value) &#123;</span><br><span class="line">    if(value != null) &#123;</span><br><span class="line">      //...</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如同类名所示, 这个Demo是模拟 boxing 的。为了 null 值判断, 使用的是包装类型 <code>Double</code>。 程序基于传感器的最新值进行计算, 但从传感器取值是一个重量级操作, 所以采用了异步方式： 一个线程不断获取新值, 计算线程则直接使用暂存的最新值, 从而避免同步等待。</p><p><a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/Boxing.java">Demo 程序</a>在运行的过程中, 由于分配速率太大而受到GC的影响。下一节将确认问题, 并给出解决办法。</p><h3 id="高分配速率对JVM的影响"><a href="#高分配速率对JVM的影响" class="headerlink" title="高分配速率对JVM的影响"></a>高分配速率对JVM的影响</h3><p>首先，我们应该检查程序的吞吐量是否降低。如果创建了过多的临时对象, minor GC的次数就会增加。如果并发较大, 则GC可能会严重影响吞吐量。</p><p>遇到这种情况时, GC日志将会像下面这样，当然这是上面的<a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/Boxing.java">示例程序</a> 产生的GC日志。 JVM启动参数为 <code>-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xmx32m</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">2.808: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 9760K-&gt;32K(10240K)], 0.0003076 secs]</span><br><span class="line">2.819: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 9760K-&gt;32K(10240K)], 0.0003079 secs]</span><br><span class="line">2.830: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 9760K-&gt;32K(10240K)], 0.0002968 secs]</span><br><span class="line">2.842: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 9760K-&gt;32K(10240K)], 0.0003374 secs]</span><br><span class="line">2.853: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 9760K-&gt;32K(10240K)], 0.0004672 secs]</span><br><span class="line">2.864: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 9760K-&gt;32K(10240K)], 0.0003371 secs]</span><br><span class="line">2.875: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 9760K-&gt;32K(10240K)], 0.0003214 secs]</span><br><span class="line">2.886: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 9760K-&gt;32K(10240K)], 0.0003374 secs]</span><br><span class="line">2.896: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 9760K-&gt;32K(10240K)], 0.0003588 secs]</span><br></pre></td></tr></table></figure><p>很显然 minor GC 的频率太高了。这说明创建了大量的对象。另外, 年轻代在 GC 之后的使用量又很低, 也没有 full GC 发生。 种种迹象表明, GC对吞吐量造成了严重的影响。</p><h3 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h3><p>在某些情况下,只要增加年轻代的大小, 即可降低分配速率过高所造成的影响。增加年轻代空间并不会降低分配速率, 但是会减少GC的频率。如果每次GC后只有少量对象存活, minor GC 的暂停时间就不会明显增加。</p><p>运行 <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/Boxing.java">示例程序</a> 时, 增加堆内存大小,(同时也就增大了年轻代的大小), 使用的JVM参数为 <code>-Xmx64m</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">2.808: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 20512K-&gt;32K(20992K)], 0.0003748 secs]</span><br><span class="line">2.831: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 20512K-&gt;32K(20992K)], 0.0004538 secs]</span><br><span class="line">2.855: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 20512K-&gt;32K(20992K)], 0.0003355 secs]</span><br><span class="line">2.879: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 20512K-&gt;32K(20992K)], 0.0005592 secs]</span><br></pre></td></tr></table></figure><p>但有时候增加堆内存的大小,并不能解决问题。通过前面学到的知识, 我们可以通过分配分析器找出大部分垃圾产生的位置。实际上在此示例中, 99%的对象属于 <code>Double</code> 包装类, 在<code>readSensor</code> 方法中创建。最简单的优化, 将创建的 <code>Double</code> 对象替换为原生类型 <code>double</code>, 而针对 null 值的检测, 可以使用 <a target="_blank" rel="noopener external nofollow noreferrer" href="https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html#NaN">Double.NaN</a> 来进行。由于原生类型不算是对象, 也就不会产生垃圾, 导致GC事件。优化之后, 不在堆中分配新对象, 而是直接覆盖一个属性域即可。</p><p>对示例程序进行<a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/FixedBoxing.java">简单的改造</a>( <a target="_blank" rel="noopener external nofollow noreferrer" href="https://gist.github.com/gvsmirnov/0270f0f15f9498e3b655">查看diff</a> ) 后, GC暂停基本上完全消除。有时候 JVM 也很智能, 会使用 逃逸分析技术(escape analysis technique) 来避免过度分配。简单来说,JIT编译器可以通过分析得知, 方法创建的某些对象永远都不会“逃出”此方法的作用域。这时候就不需要在堆上分配这些对象, 也就不会产生垃圾, 所以JIT编译器的一种优化手段就是: 消除内存分配。请参考 <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/jit/EscapeAnalysis.java">基准测试</a> 。</p><h2 id="过早提升-Premature-Promotion"><a href="#过早提升-Premature-Promotion" class="headerlink" title="过早提升(Premature Promotion)"></a>过早提升(Premature Promotion)</h2><p><strong>提升速率</strong>(<code>promotion rate</code>), 用于衡量单位时间内从年轻代提升到老年代的数据量。一般使用 <code>MB/sec</code> 作为单位, 和<code>分配速率</code>类似。</p><p>JVM会将长时间存活的对象从年轻代提升到老年代。根据分代假设, 可能存在一种情况, 老年代中不仅有存活时间长的对象,也可能有存活时间短的对象。这就是过早提升：对象存活时间还不够长的时候就被提升到了老年代。</p><p>major GC 不是为频繁回收而设计的, 但 major GC 现在也要清理这些生命短暂的对象, 就会导致GC暂停时间过长。这会严重影响系统的吞吐量。</p><h3 id="如何测量提升速率"><a href="#如何测量提升速率" class="headerlink" title="如何测量提升速率"></a>如何测量提升速率</h3><p>可以指定JVM参数 <code>-XX:+PrintGCDetails -XX:+PrintGCTimeStamps</code> , 通过GC日志来测量提升速率. JVM记录的GC暂停信息如下所示:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">0.291: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 33280K-&gt;5088K(38400K)] </span><br><span class="line">        33280K-&gt;24360K(125952K), 0.0365286 secs] </span><br><span class="line">    [Times: user=0.11 sys=0.02, real=0.04 secs] </span><br><span class="line">0.446: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 38368K-&gt;5120K(71680K)] </span><br><span class="line">        57640K-&gt;46240K(159232K), 0.0456796 secs] </span><br><span class="line">    [Times: user=0.15 sys=0.02, real=0.04 secs] </span><br><span class="line">0.829: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 71680K-&gt;5120K(71680K)] </span><br><span class="line">        112800K-&gt;81912K(159232K), 0.0861795 secs] </span><br><span class="line">    [Times: user=0.23 sys=0.03, real=0.09 secs]</span><br></pre></td></tr></table></figure><p>从上面的日志可以得知： GC之前和之后的 年轻代使用量以及堆内存使用量。这样就可以通过差值算出老年代的使用量。GC日志中的信息可以表述为:</p><table><thead><tr><th align="center"><strong>Event</strong></th><th align="center"><strong>Time</strong></th><th align="center"><strong>Young decreased</strong></th><th align="center"><strong>Total decreased</strong></th><th align="center"><strong>Promoted</strong></th><th align="center"><strong>Promotion rate</strong></th></tr></thead><tbody><tr><td align="center"><strong>(事件)</strong></td><td align="center"><strong>(耗时)</strong></td><td align="center"><strong>(年轻代减少)</strong></td><td align="center"><strong>(整个堆内存减少)</strong></td><td align="center"><strong>(提升量)</strong></td><td align="center"><strong>(提升速率)</strong></td></tr><tr><td align="center">1st GC</td><td align="center">291ms</td><td align="center">28,192K</td><td align="center">8,920K</td><td align="center">19,272K</td><td align="center"><strong>66.2 MB&#x2F;sec</strong></td></tr><tr><td align="center">2nd GC</td><td align="center">446ms</td><td align="center">33,248K</td><td align="center">11,400K</td><td align="center">21,848K</td><td align="center"><strong>140.95 MB&#x2F;sec</strong></td></tr><tr><td align="center">3rd GC</td><td align="center">829ms</td><td align="center">66,560K</td><td align="center">30,888K</td><td align="center">35,672K</td><td align="center"><strong>93.14 MB&#x2F;sec</strong></td></tr><tr><td align="center">Total</td><td align="center">829ms</td><td align="center"></td><td align="center"></td><td align="center">76,792K</td><td align="center"><strong>92.63 MB&#x2F;sec</strong></td></tr></tbody></table><p>根据这些信息, 就可以计算出观测周期内的提升速率。平均提升速率为 <code>92 MB/秒</code>, 峰值为 <code>140.95 MB/秒</code>。</p><p>请注意, <strong>只能根据 minor GC 计算提升速率</strong>。 Full GC 的日志不能用于计算提升速率, 因为 major GC 会清理掉老年代中的一部分对象。</p><h3 id="提升速率的意义"><a href="#提升速率的意义" class="headerlink" title="提升速率的意义"></a>提升速率的意义</h3><p>和分配速率一样, 提升速率也会影响GC暂停的频率。但分配速率主要影响 <a target="_blank" rel="noopener external nofollow noreferrer" href="http://blog.csdn.net/renfufei/article/details/54144385#t8">minor GC</a>, 而提升速率则影响 <a target="_blank" rel="noopener external nofollow noreferrer" href="http://blog.csdn.net/renfufei/article/details/54144385#t8">major GC</a> 的频率。有大量的对象提升,自然很快将老年代填满。 老年代填充的越快, 则 major GC 事件的频率就会越高。</p><p><img src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://s3.uuu.ovh/imgs/2022/05/10/61804bf2eb586a91.png" alt="img_1.png"></p><p>此前说过, full GC 通常需要更多的时间, 因为需要处理更多的对象, 还要执行碎片整理等额外的复杂过程。</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例"></a>示例</h3><p>让我们看一个<a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/PrematurePromotion.java">过早提升的示例</a>。 这个程序创建&#x2F;获取大量的对象&#x2F;数据,并暂存到集合之中, 达到一定数量后进行批处理:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">public class PrematurePromotion &#123;</span><br><span class="line"></span><br><span class="line">   private static final Collection&lt;byte[]&gt; accumulatedChunks </span><br><span class="line">                = new ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">   private static void onNewChunk(byte[] bytes) &#123;</span><br><span class="line">       accumulatedChunks.add(bytes);</span><br><span class="line"></span><br><span class="line">       if(accumulatedChunks.size() &gt; MAX_CHUNKS) &#123;</span><br><span class="line">           processBatch(accumulatedChunks);</span><br><span class="line">           accumulatedChunks.clear();</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>此 <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/PrematurePromotion.java">Demo 程序</a> 受到过早提升的影响。下文将进行验证并给出解决办法。</p><h3 id="过早提升的影响"><a href="#过早提升的影响" class="headerlink" title="过早提升的影响"></a>过早提升的影响</h3><p>一般来说,过早提升的症状表现为以下形式:</p><ul><li>短时间内频繁地执行 full GC。</li><li>每次 full GC 后老年代的使用率都很低, 在10-20%或以下。</li><li>提升速率接近于分配速率。</li></ul><p>要演示这种情况稍微有点麻烦, 所以我们使用特殊手段, 让对象提升到老年代的年龄比默认情况小很多。指定GC参数 <code>-Xmx24m -XX:NewSize=16m -XX:MaxTenuringThreshold=1</code>, 运行程序之后,可以看到下面的GC日志:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">2.176: [Full GC (Ergonomics) </span><br><span class="line">        [PSYoungGen: 9216K-&gt;0K(10752K)] </span><br><span class="line">        [ParOldGen: 10020K-&gt;9042K(12288K)] </span><br><span class="line">        19236K-&gt;9042K(23040K), 0.0036840 secs]</span><br><span class="line">2.394: [Full GC (Ergonomics) </span><br><span class="line">        [PSYoungGen: 9216K-&gt;0K(10752K)] </span><br><span class="line">        [ParOldGen: 9042K-&gt;8064K(12288K)] </span><br><span class="line">        18258K-&gt;8064K(23040K), 0.0032855 secs]</span><br><span class="line">2.611: [Full GC (Ergonomics) </span><br><span class="line">        [PSYoungGen: 9216K-&gt;0K(10752K)] </span><br><span class="line">        [ParOldGen: 8064K-&gt;7085K(12288K)] </span><br><span class="line">        17280K-&gt;7085K(23040K), 0.0031675 secs]</span><br><span class="line">2.817: [Full GC (Ergonomics) </span><br><span class="line">        [PSYoungGen: 9216K-&gt;0K(10752K)] </span><br><span class="line">        [ParOldGen: 7085K-&gt;6107K(12288K)] </span><br><span class="line">        16301K-&gt;6107K(23040K), 0.0030652 secs]</span><br></pre></td></tr></table></figure><p>乍一看似乎不是过早提升的问题。事实上,在每次GC之后老年代的使用率似乎在减少。但反过来想, 要是没有对象提升或者提升率很小, 也就不会看到这么多的 Full GC 了。</p><p>简单解释一下这里的GC行为: 有很多对象提升到老年代, 同时老年代中也有很多对象被回收了, 这就造成了老年代使用量减少的假象. 但事实是大量的对象不断地被提升到老年代, 并触发 full GC。</p><h3 id="解决方案-1"><a href="#解决方案-1" class="headerlink" title="解决方案"></a>解决方案</h3><p>简单来说, 要解决这类问题, 需要让年轻代存放得下暂存的数据。有两种简单的方法:</p><p>一是增加年轻代的大小, 设置JVM启动参数, 类似这样: <code>-Xmx64m -XX:NewSize=32m</code>, 程序在执行时, Full GC 的次数自然会减少很多, 只会对 minor GC的持续时间产生影响:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">2.251: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 28672K-&gt;3872K(28672K)] </span><br><span class="line">        37126K-&gt;12358K(61440K), 0.0008543 secs]</span><br><span class="line">2.776: [GC (Allocation Failure) </span><br><span class="line">        [PSYoungGen: 28448K-&gt;4096K(28672K)] </span><br><span class="line">        36934K-&gt;16974K(61440K), 0.0033022 secs]</span><br></pre></td></tr></table></figure><p>二是减少每次批处理的数量, 也能得到类似的结果. 至于选用哪个方案, 要根据业务需求决定。在某些情况下, 业务逻辑不允许减少批处理的数量, 那就只能增加堆内存,或者重新指定年轻代的大小。</p><p>如果都不可行, 就只能优化数据结构, 减少内存消耗。但总体目标依然是一致的: 让临时数据能够在年轻代存放得下。</p><h2 id="Weak-Soft-及-Phantom-引用"><a href="#Weak-Soft-及-Phantom-引用" class="headerlink" title="Weak, Soft 及 Phantom 引用"></a>Weak, Soft 及 Phantom 引用</h2><p>另一类影响GC的问题是程序中的 <code>non-strong 引用</code>。虽然这类引用在很多情况下可以避免出现 <a target="_blank" rel="noopener external nofollow noreferrer" href="https://plumbr.eu/outofmemory"><code>OutOfMemoryError</code></a>, 但过量使用也会对GC造成严重的影响, 反而降低系统性能。</p><h2 id="弱引用的缺点"><a href="#弱引用的缺点" class="headerlink" title="弱引用的缺点"></a>弱引用的缺点</h2><p>首先, <code>弱引用</code>(<code>weak reference</code>) 是可以被GC强制回收的。当垃圾收集器发现一个弱可达对象(<code>weakly reachable</code>,即指向该对象的引用只剩下弱引用) 时, 就会将其置入相应的<code>ReferenceQueue</code> 中, 变成可终结的对象. 之后可能会遍历这个 reference queue, 并执行相应的清理。典型的示例是清除缓存中不再引用的KEY。</p><p>当然, 在这个时候, 我们还可以将该对象赋值给新的强引用, 在最后终结和回收前, GC会再次确认该对象是否可以安全回收。因此, 弱引用对象的回收过程是横跨多个GC周期的。</p><p>实际上弱引用使用的很多。大部分缓存框架(<strong>caching solution</strong>)都是基于弱引用实现的, 所以虽然业务代码中没有直接使用弱引用, 但程序中依然会大量存在。</p><p>其次, <code>软引用</code>(soft reference) 比弱引用更难被垃圾收集器回收. 回收软引用没有确切的时间点, 由JVM自己决定. 一般只会在即将耗尽可用内存时, 才会回收软引用,以作最后手段。这意味着, 可能会有更频繁的 full GC, 暂停时间也比预期更长, 因为老年代中的存活对象会很多。</p><p>最后, 使用<code>虚引用</code>(phantom reference)时, 必须手动进行内存管理, 以标识这些对象是否可以安全地回收。表面上看起来很正常, 但实际上并不是这样。 javadoc 中写道:</p><blockquote><p>In order to ensure that a reclaimable object remains so, the referent of a phantom reference may not be retrieved: The get method of a phantom reference always returns null.</p><p>为了防止可回收对象的残留, 虚引用对象不应该被获取: <code>phantom reference</code> 的 <code>get</code> 方法返回值永远是 <code>null</code>。</p></blockquote><p>令人惊讶的是, 很多开发者忽略了下一段内容(<strong>这才是重点</strong>):</p><blockquote><p>Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.</p><p>与软引用和弱引用不同, 虚引用不会被 GC 自动清除, 因为他们被存放到队列中. 通过虚引用可达的对象会继续留在内存中, 直到调用此引用的 clear 方法, 或者引用自身变为不可达。</p></blockquote><p>也就是说,我们必须手动调用 <a target="_blank" rel="noopener external nofollow noreferrer" href="http://docs.oracle.com/javase/7/docs/api/java/lang/ref/Reference.html#clear()">clear()</a> 来清除虚引用, 否则可能会造成 <a target="_blank" rel="noopener external nofollow noreferrer" href="https://plumbr.eu/outofmemory">OutOfMemoryError</a> 而导致 JVM 挂掉. 使用虚引用的理由是, 对于用编程手段来跟踪某个对象何时变为不可达对象, 这是唯一的常规手段。 和软引用&#x2F;弱引用不同的是, 我们不能复活虚可达(phantom-reachable)对象。</p><h2 id="示例-2"><a href="#示例-2" class="headerlink" title="示例"></a>示例</h2><p>让我们看<a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/WeakReferences.java">一个弱引用示例</a>, 其中创建了大量的对象, 并在 minor GC 中完成回收。和前面一样, 修改提升阀值。使用的JVM参数为: <code>-Xmx24m -XX:NewSize=16m -XX:MaxTenuringThreshold=1</code> , GC日志如下所示:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">2.330: [GC (Allocation Failure)  20933K-&gt;8229K(22528K), 0.0033848 secs]</span><br><span class="line">2.335: [GC (Allocation Failure)  20517K-&gt;7813K(22528K), 0.0022426 secs]</span><br><span class="line">2.339: [GC (Allocation Failure)  20101K-&gt;7429K(22528K), 0.0010920 secs]</span><br><span class="line">2.341: [GC (Allocation Failure)  19717K-&gt;9157K(22528K), 0.0056285 secs]</span><br><span class="line">2.348: [GC (Allocation Failure)  21445K-&gt;8997K(22528K), 0.0041313 secs]</span><br><span class="line">2.354: [GC (Allocation Failure)  21285K-&gt;8581K(22528K), 0.0033737 secs]</span><br><span class="line">2.359: [GC (Allocation Failure)  20869K-&gt;8197K(22528K), 0.0023407 secs]</span><br><span class="line">2.362: [GC (Allocation Failure)  20485K-&gt;7845K(22528K), 0.0011553 secs]</span><br><span class="line">2.365: [GC (Allocation Failure)  20133K-&gt;9501K(22528K), 0.0060705 secs]</span><br><span class="line">2.371: [Full GC (Ergonomics)  9501K-&gt;2987K(22528K), 0.0171452 secs]</span><br></pre></td></tr></table></figure><p>可以看到, Full GC 的次数很少。但如果使用弱引用来指向创建的对象, 使用JVM参数 <code>-Dweak.refs=true</code>, 则情况会发生明显变化. 使用弱引用的原因很多, 比如在 weak hash map 中将对象作为Key的情况。在任何情况下, 使用弱引用都可能会导致以下情形:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">2.059: [Full GC (Ergonomics)  20365K-&gt;19611K(22528K), 0.0654090 secs]</span><br><span class="line">2.125: [Full GC (Ergonomics)  20365K-&gt;19711K(22528K), 0.0707499 secs]</span><br><span class="line">2.196: [Full GC (Ergonomics)  20365K-&gt;19798K(22528K), 0.0717052 secs]</span><br><span class="line">2.268: [Full GC (Ergonomics)  20365K-&gt;19873K(22528K), 0.0686290 secs]</span><br><span class="line">2.337: [Full GC (Ergonomics)  20365K-&gt;19939K(22528K), 0.0702009 secs]</span><br><span class="line">2.407: [Full GC (Ergonomics)  20365K-&gt;19995K(22528K), 0.0694095 secs]</span><br></pre></td></tr></table></figure><p>可以看到, 发生了多次 full GC, 比起前一节的示例, GC时间增加了一个数量级! 这是过早提升的另一个例子, 但这次情况更加棘手. 当然,问题的根源在于弱引用。这些临死的对象, 在添加弱引用之后, 被提升到了老年代。 但是, 他们现在陷入另一次GC循环之中, 所以需要对其做一些适当的清理。像之前一样, 最简单的办法是增加年轻代的大小, 例如指定JVM参数: <code>-Xmx64m -XX:NewSize=32m</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">2.328: [GC (Allocation Failure)  38940K-&gt;13596K(61440K), 0.0012818 secs]</span><br><span class="line">2.332: [GC (Allocation Failure)  38172K-&gt;14812K(61440K), 0.0060333 secs]</span><br><span class="line">2.341: [GC (Allocation Failure)  39388K-&gt;13948K(61440K), 0.0029427 secs]</span><br><span class="line">2.347: [GC (Allocation Failure)  38524K-&gt;15228K(61440K), 0.0101199 secs]</span><br><span class="line">2.361: [GC (Allocation Failure)  39804K-&gt;14428K(61440K), 0.0040940 secs]</span><br><span class="line">2.368: [GC (Allocation Failure)  39004K-&gt;13532K(61440K), 0.0012451 secs]</span><br></pre></td></tr></table></figure><p>这时候, 对象在 minor GC 中就被回收了。</p><p>更坏的情况是使用软引用,例如这个<a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/SoftReferences.java">软引用示例程序</a>。如果程序不是即将发生 <code>OutOfMemoryError</code> , 软引用对象就不会被回收. 在示例程序中,用软引用替代弱引用, 立即出现了更多的 Full GC 事件:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">2.162: [Full GC (Ergonomics)  31561K-&gt;12865K(61440K), 0.0181392 secs]</span><br><span class="line">2.184: [GC (Allocation Failure)  37441K-&gt;17585K(61440K), 0.0024479 secs]</span><br><span class="line">2.189: [GC (Allocation Failure)  42161K-&gt;27033K(61440K), 0.0061485 secs]</span><br><span class="line">2.195: [Full GC (Ergonomics)  27033K-&gt;14385K(61440K), 0.0228773 secs]</span><br><span class="line">2.221: [GC (Allocation Failure)  38961K-&gt;20633K(61440K), 0.0030729 secs]</span><br><span class="line">2.227: [GC (Allocation Failure)  45209K-&gt;31609K(61440K), 0.0069772 secs]</span><br><span class="line">2.234: [Full GC (Ergonomics)  31609K-&gt;15905K(61440K), 0.0257689 secs]</span><br></pre></td></tr></table></figure><p>最有趣的是<a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/PhantomReferences.java">虚引用示例</a>中的虚引用, 使用同样的JVM参数启动, 其结果和弱引用示例非常相似。实际上, full GC 暂停的次数会小得多, 原因前面说过, 他们有不同的终结方式。</p><p>如果禁用虚引用清理, 增加JVM启动参数 (<code>-Dno.ref.clearing=true</code>), 则可以看到:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">4.180: [Full GC (Ergonomics)  57343K-&gt;57087K(61440K), 0.0879851 secs]</span><br><span class="line">4.269: [Full GC (Ergonomics)  57089K-&gt;57088K(61440K), 0.0973912 secs]</span><br><span class="line">4.366: [Full GC (Ergonomics)  57091K-&gt;57089K(61440K), 0.0948099 secs]</span><br></pre></td></tr></table></figure><p>main 线程中抛出异常 <code>java.lang.OutOfMemoryError: Java heap space</code>.</p><p>使用虚引用时要小心谨慎, 并及时清理虚可达对象。如果不清理, 很可能会发生 <a target="_blank" rel="noopener external nofollow noreferrer" href="https://plumbr.eu/outofmemory"><code>OutOfMemoryError</code></a>. 请相信我们的经验教训: 处理 reference queue 的线程中如果没 catch 住 exception , 系统很快就会被整挂了。</p><h3 id="使用非强引用的影响"><a href="#使用非强引用的影响" class="headerlink" title="使用非强引用的影响"></a>使用非强引用的影响</h3><p>建议使用JVM参数 <code>-XX:+PrintReferenceGC</code> 来看看各种引用对GC的影响. 如果将此参数用于启动 <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/gvsmirnov/java-perv/blob/master/labs-8/src/main/java/ru/gvsmirnov/perv/labs/gc/WeakReferences.java">弱引用示例</a> , 将会看到:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">2.173: [Full GC (Ergonomics) </span><br><span class="line">        2.234: [SoftReference, 0 refs, 0.0000151 secs]</span><br><span class="line">        2.234: [WeakReference, 2648 refs, 0.0001714 secs]</span><br><span class="line">        2.234: [FinalReference, 1 refs, 0.0000037 secs]</span><br><span class="line">        2.234: [PhantomReference, 0 refs, 0 refs, 0.0000039 secs]</span><br><span class="line">        2.234: [JNI Weak Reference, 0.0000027 secs]</span><br><span class="line">            [PSYoungGen: 9216K-&gt;8676K(10752K)] </span><br><span class="line">            [ParOldGen: 12115K-&gt;12115K(12288K)] </span><br><span class="line">            21331K-&gt;20792K(23040K), </span><br><span class="line">        [Metaspace: 3725K-&gt;3725K(1056768K)], </span><br><span class="line">        0.0766685 secs] </span><br><span class="line">    [Times: user=0.49 sys=0.01, real=0.08 secs] </span><br><span class="line">2.250: [Full GC (Ergonomics) </span><br><span class="line">        2.307: [SoftReference, 0 refs, 0.0000173 secs]</span><br><span class="line">        2.307: [WeakReference, 2298 refs, 0.0001535 secs]</span><br><span class="line">        2.307: [FinalReference, 3 refs, 0.0000043 secs]</span><br><span class="line">        2.307: [PhantomReference, 0 refs, 0 refs, 0.0000042 secs]</span><br><span class="line">        2.307: [JNI Weak Reference, 0.0000029 secs]</span><br><span class="line">            [PSYoungGen: 9215K-&gt;8747K(10752K)] </span><br><span class="line">            [ParOldGen: 12115K-&gt;12115K(12288K)] </span><br><span class="line">            21331K-&gt;20863K(23040K), </span><br><span class="line">        [Metaspace: 3725K-&gt;3725K(1056768K)], </span><br><span class="line">        0.0734832 secs] </span><br><span class="line">    [Times: user=0.52 sys=0.01, real=0.07 secs] </span><br><span class="line">2.323: [Full GC (Ergonomics) </span><br><span class="line">        2.383: [SoftReference, 0 refs, 0.0000161 secs]</span><br><span class="line">        2.383: [WeakReference, 1981 refs, 0.0001292 secs]</span><br><span class="line">        2.383: [FinalReference, 16 refs, 0.0000049 secs]</span><br><span class="line">        2.383: [PhantomReference, 0 refs, 0 refs, 0.0000040 secs]</span><br><span class="line">        2.383: [JNI Weak Reference, 0.0000027 secs]</span><br><span class="line">            [PSYoungGen: 9216K-&gt;8809K(10752K)] </span><br><span class="line">            [ParOldGen: 12115K-&gt;12115K(12288K)] </span><br><span class="line">            21331K-&gt;20925K(23040K), </span><br><span class="line">        [Metaspace: 3725K-&gt;3725K(1056768K)], </span><br><span class="line">        0.0738414 secs] </span><br><span class="line">    [Times: user=0.52 sys=0.01, real=0.08 secs]</span><br></pre></td></tr></table></figure><p>只有确定 GC 对应用的吞吐量和延迟造成影响之后, 才应该花心思来分析这些信息, 审查这部分日志。通常情况下, 每次GC清理的引用数量都是很少的, 大部分情况下为 <code>0</code>。如果GC 花了较多时间来清理这类引用, 或者清除了很多的此类引用, 就需要进一步观察和分析了。</p><h3 id="解决方案-2"><a href="#解决方案-2" class="headerlink" title="解决方案"></a>解决方案</h3><p>如果程序确实碰到了 <code>mis-</code>, <code>ab-</code> 问题或者滥用 weak, soft, phantom 引用, 一般都要修改程序的实现逻辑。每个系统不一样, 因此很难提供通用的指导建议, 但有一些常用的办法:</p><ul><li><code>弱引用</code>(<code>Weak references</code>) —— 如果某个内存池的使用量增大, 造成了性能问题, 那么增加这个内存池的大小(可能也要增加堆内存的最大容量)。如同示例中所看到的, 增加堆内存的大小, 以及年轻代的大小, 可以减轻症状。</li><li><code>虚引用</code>(<code>Phantom references</code>) —— 请确保在程序中调用了虚引用的 <code>clear</code> 方法。编程中很容易忽略某些虚引用, 或者清理的速度跟不上生产的速度, 又或者清除引用队列的线程挂了, 就会对GC 造成很大压力, 最终可能引起 <a target="_blank" rel="noopener external nofollow noreferrer" href="http://www.oracle.com/technetwork/articles/javaee/index-jsp-136424.html"><code>OutOfMemoryError</code></a>。</li><li><code>软引用</code>(<code>Soft references</code>) —— 如果确定问题的根源是软引用, 唯一的解决办法是修改程序源码, 改变内部实现逻辑。</li></ul><h2 id="其他示例"><a href="#其他示例" class="headerlink" title="其他示例"></a>其他示例</h2><p>前面介绍了最常见的GC性能问题。但我们学到的很多原理都没有具体的场景来展现。本节介绍一些不常发生, 但也可能会碰到的问题。</p><h3 id="RMI-与-GC"><a href="#RMI-与-GC" class="headerlink" title="RMI 与 GC"></a>RMI 与 GC</h3><p>如果系统提供或者消费 <a target="_blank" rel="noopener external nofollow noreferrer" href="http://www.oracle.com/technetwork/articles/javaee/index-jsp-136424.html">RMI</a> 服务, 则JVM会定期执行 full GC 来确保本地未使用的对象在另一端也不占用空间. 记住, 即使你的代码中没有发布 RMI 服务, 但第三方或者工具库也可能会打开 RMI 终端. 最常见的元凶是 JMX, 如果通过JMX连接到远端, 底层则会使用 RMI 发布数据。</p><p>问题是有很多不必要的周期性 full GC。查看老年代的使用情况, 一般是没有内存压力, 其中还存在大量的空闲区域, 但 full GC 就是被触发了, 也就会暂停所有的应用线程。</p><p>这种周期性调用 <code>System.gc()</code> 删除远程引用的行为, 是在 <code>sun.rmi.transport.ObjectTable</code> 类中, 通过 <code>sun.misc.GC.requestLatency(long gcInterval)</code> 调用的。</p><p>对许多应用来说, 根本没必要, 甚至对性能有害。 禁止这种周期性的 GC 行为, 可以使用以下 JVM 参数:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">java -Dsun.rmi.dgc.server.gcInterval=9223372036854775807L </span><br><span class="line">    -Dsun.rmi.dgc.client.gcInterval=9223372036854775807L </span><br><span class="line">    com.yourcompany.YourApplication</span><br></pre></td></tr></table></figure><p>这让 <code>Long.MAX_VALUE</code> 毫秒之后, 才调用 <a target="_blank" rel="noopener external nofollow noreferrer" href="http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#gc()"><code>System.gc()</code></a>, 实际运行的系统可能永远都不会触发。</p><blockquote><p>ObjectTable.class</p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">private static final long gcInterval = </span><br><span class="line">((Long)AccessController.doPrivileged(</span><br><span class="line">    new GetLongAction(&quot;sun.rmi.dgc.server.gcInterval&quot;, 3600000L)</span><br><span class="line">    )).longValue();</span><br></pre></td></tr></table></figure><p>可以看到, 默认值为 <code>3600000L</code>,也就是1小时触发一次 Full GC。</p><p>另一种方式是指定JVM参数 <code>-XX:+DisableExplicitGC</code>, 禁止显式地调用 <code>System.gc()</code>. 但我们<strong>强烈反对</strong> 这种方式, 因为埋有地雷。</p><h3 id="JVMTI-tagging-与-GC"><a href="#JVMTI-tagging-与-GC" class="headerlink" title="JVMTI tagging 与 GC"></a>JVMTI tagging 与 GC</h3><p>如果在程序启动时指定了 Java Agent (<code>-javaagent</code>), agent 就可以使用 <a target="_blank" rel="noopener external nofollow noreferrer" href="http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#Heap">JVMTI tagging</a> 标记堆中的对象。agent 使用tagging的种种原因本手册不详细讲解, 但如果 tagging 标记了大量的对象, 很可能会引起 GC 性能问题, 导致延迟增加, 以及吞吐量降低。</p><p>问题发生在 native 代码中, <code>JvmtiTagMap::do_weak_oops</code> 在每次GC时, 都会遍历所有标签(tag),并执行一些比较耗时的操作。更坑的是, 这种操作是串行执行的。</p><p>如果存在大量的标签, 就意味着 GC 时有很大一部分工作是单线程执行的, GC暂停时间可能会增加一个数量级。</p><p>检查是否因为 agent 增加了GC暂停时间, 可以使用诊断参数 <code>–XX:+TraceJVMTIObjectTagging</code>. 启用跟踪之后, 可以估算出内存中 tag 映射了多少 native 内存, 以及遍历所消耗的时间。</p><p>如果你不是 agent 的作者, 那一般是搞不定这类问题的。除了提BUG之外你什么都做不了. 如果发生了这种情况, 请建议厂商清理不必要的标签。</p><h3 id="巨无霸对象的分配-Humongous-Allocations"><a href="#巨无霸对象的分配-Humongous-Allocations" class="headerlink" title="巨无霸对象的分配(Humongous Allocations)"></a>巨无霸对象的分配(Humongous Allocations)</h3><p>如果使用 G1 垃圾收集算法, 会产生一种巨无霸对象引起的 GC 性能问题。</p><blockquote><p><strong>说明</strong>: 在G1中, 巨无霸对象是指所占空间超过一个小堆区(region) <code>50%</code> 的对象。</p></blockquote><p>频繁的创建巨无霸对象, 无疑会造成GC的性能问题, 看看G1的处理方式:</p><ul><li>如果某个 region 中含有巨无霸对象, 则巨无霸对象后面的空间将不会被分配。如果所有巨无霸对象都超过某个比例, 则未使用的空间就会引发内存碎片问题。</li><li>G1 没有对巨无霸对象进行优化。这在 JDK 8 以前是个特别棘手的问题 —— 在 <a target="_blank" rel="noopener external nofollow noreferrer" href="https://bugs.openjdk.java.net/browse/JDK-8027959"><strong>Java 1.8u40</strong></a> 之前的版本中, 巨无霸对象所在 region 的回收只能在 full GC 中进行。最新版本的 Hotspot JVM, 在 marking 阶段之后的 cleanup 阶段中释放巨无霸区间, 所以这个问题在新版本JVM中的影响已大大降低。</li></ul><p>要监控是否存在巨无霸对象, 可以打开GC日志, 使用的命令如下:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">java -XX:+PrintGCDetails -XX:+PrintGCTimeStamps </span><br><span class="line">    -XX:+PrintReferenceGC -XX:+UseG1GC </span><br><span class="line">    -XX:+PrintAdaptiveSizePolicy -Xmx128m </span><br><span class="line">    MyClass</span><br></pre></td></tr></table></figure><p>GC 日志中可能会发现这样的部分:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">0.106: [G1Ergonomics (Concurrent Cycles) </span><br><span class="line">       request concurrent cycle initiation, </span><br><span class="line">       reason: occupancy higher than threshold, </span><br><span class="line">       occupancy: 60817408 bytes, </span><br><span class="line">       allocation request: 1048592 bytes, </span><br><span class="line">       threshold: 60397965 bytes (45.00 %), </span><br><span class="line">       source: concurrent humongous allocation]</span><br><span class="line">0.106: [G1Ergonomics (Concurrent Cycles) </span><br><span class="line">       request concurrent cycle initiation, </span><br><span class="line">       reason: requested by GC cause, </span><br><span class="line">       GC cause: G1 Humongous Allocation]</span><br><span class="line">0.106: [G1Ergonomics (Concurrent Cycles) </span><br><span class="line">       initiate concurrent cycle, </span><br><span class="line">       reason: concurrent cycle initiation requested]</span><br><span class="line">0.106: [GC pause (G1 Humongous Allocation) </span><br><span class="line">       (young) (initial-mark) </span><br><span class="line">       0.106: [G1Ergonomics (CSet Construction) </span><br><span class="line">           start choosing CSet, </span><br><span class="line">           _pending_cards: 0, </span><br><span class="line">           predicted base </span><br><span class="line">           time: 10.00 ms, </span><br><span class="line">           remaining time: 190.00 ms, </span><br><span class="line">           target pause time: 200.00 ms]</span><br></pre></td></tr></table></figure><p>这样的日志就是证据, 表明程序中确实创建了巨无霸对象. 可以看到: <code>G1 Humongous Allocation</code> 是 GC暂停的原因。 再看前面一点的 <code>allocation request: 1048592 bytes</code> , 可以发现程序试图分配一个 <code>1,048,592</code> 字节的对象, 这要比巨无霸区域(<code>2MB</code>)的 <code>50%</code> 多出 16 个字节。</p><p>第一种解决方式, 是修改 region size , 以使得大多数的对象不超过 <code>50%</code>, 也就不进行巨无霸对象区域的分配。 region 的默认大小在启动时根据堆内存的大小算出。但也可以指定参数来覆盖默认设置, <code>-XX:G1HeapRegionSize=XX</code>。 指定的 region size 必须在 <code>1~32MB</code> 之间, 还必须是2的幂 【2^10 &#x3D; 1024 &#x3D; 1KB; 2^20&#x3D;1MB; 所以 region size 只能是: <code>1m</code>,<code>2m</code>,<code>4m</code>,<code>8m</code>,<code>16m</code>,<code>32m</code>】。</p><p>这种方式也有副作用, 增加 region 的大小也就变相地减少了 region 的数量, 所以需要谨慎使用, 最好进行一些测试, 看看是否改善了吞吐量和延迟。</p><p>更好的方式需要一些工作量, 如果可以的话, 在程序中限制对象的大小。最好是使用分析器, 展示出巨无霸对象的信息, 以及分配时所在的堆栈跟踪信息。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>JVM上运行的程序多种多样, 启动参数也有上百个, 其中有很多会影响到 GC, 所以调优GC性能的方法也有很多种。</p><p>还是那句话, 没有真正的银弹, 能满足所有的性能调优指标。 我们能做的只是介绍一些常见的&#x2F;和不常见的示例, 让你在碰到类似问题时知道是怎么回事。深入理解GC的工作原理, 熟练应用各种工具, 就可以进行GC调优, 提高程序性能。</p></article><div class="post-copyright"><div class="copyright-cc-box"><i class="anzhiyufont anzhiyu-icon-copyright"></i></div><div class="post-copyright__author_box"><a class="post-copyright__author_img" href="/" title="头像"><img class="post-copyright__author_img_back" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://q1.qlogo.cn/g?b=qq&amp;nk=2071916845&amp;s=640" title="头像" alt="头像"><img class="post-copyright__author_img_front" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://q1.qlogo.cn/g?b=qq&amp;nk=2071916845&amp;s=640" title="头像" alt="头像"></a><div class="post-copyright__author_name">云少</div><div class="post-copyright__author_desc">站在巨人的肩膀罢了</div></div><div class="post-copyright__post__info"><a class="post-copyright__original" title="该文章为原创文章，注意版权协议" href="https://it985.github.io/posts/727d80c8.html">原创</a><a class="post-copyright-title"><span onclick='rm.copyPageUrl("https://it985.github.io/posts/727d80c8.html")'>八、GC 性能优化 – GC 调优(实战篇)</span></a></div><div class="post-tools" id="post-tools"><div class="post-tools-left"><div class="rewardLeftButton"><div class="post-reward" onclick="anzhiyu.addRewardMask()"><div class="reward-button button--animated" title="赞赏作者"><i class="anzhiyufont anzhiyu-icon-hand-heart-fill"></i>打赏作者</div><div class="reward-main"><div class="reward-all"><span class="reward-title">感谢你赐予我前进的力量</span><ul class="reward-group"><li class="reward-item"><a href="/img/wxpay.webp" target="_blank"><img class="post-qr-code-img" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="/img/wxpay.webp" alt="wechat"></a><div class="post-qr-code-desc">wechat</div></li><li class="reward-item"><a href="/img/alipay.webp" target="_blank"><img class="post-qr-code-img" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="/img/alipay.webp" alt="alipay"></a><div class="post-qr-code-desc">alipay</div></li></ul><a class="reward-main-btn" href="/about/#about-reward" target="_blank"><div class="reward-text">赞赏者名单</div><div class="reward-dec">因为你们的支持让我意识到写文章的价值🙏</div></a></div></div></div><div id="quit-box" onclick="anzhiyu.removeRewardMask()" style="display:none"></div></div><div class="shareRight"><div class="share-link mobile"><div class="share-qrcode"><div class="share-button" title="使用手机访问这篇文章"><i class="anzhiyufont anzhiyu-icon-qrcode"></i></div><div class="share-main"><div class="share-main-all"><div id="qrcode" title="https://it985.github.io/posts/727d80c8.html"></div><div class="reward-dec">使用手机访问这篇文章</div></div></div></div></div><div class="share-link weibo"><a class="share-button" target="_blank" href="https://service.weibo.com/share/share.php?title=八、GC 性能优化 – GC 调优(实战篇)&amp;url=https://it985.github.io/posts/727d80c8.html&amp;pic=https://cn.bing.com/th?id=OHR.MoonJellyDay_EN-US5774626244_UHD.jpg" rel="external nofollow noreferrer noopener"><i class="anzhiyufont anzhiyu-icon-weibo"></i></a></div><div class="share-link copyurl"><div class="share-button" id="post-share-url" title="复制链接" onclick="rm.copyPageUrl()"><i class="anzhiyufont anzhiyu-icon-link"></i></div></div></div></div></div><div class="post-copyright__notice"><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="external nofollow noreferrer" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://it985.github.io" target="_blank">云少IT</a>！</span></div></div><div class="post-tools-right"><div class="tag_share"><div class="post-meta__box"><div class="post-meta__box__tag-list"><a class="post-meta__box__tags" href="/tags/JVM/"><span class="tags-punctuation"><i class="anzhiyufont anzhiyu-icon-tag"></i></span>JVM<span class="tagsPageCount">8</span></a></div></div><div class="post_share"><div class="social-share" data-image="https://img02.anheyu.com/adminuploads/1/2022/09/05/6315e146a8bbd.webp" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.cbd.int/butterfly-extsrc@1.1.3/sharejs/dist/css/share.min.css" media="print" onload='this.media="all"'><script src="https://cdn.cbd.int/butterfly-extsrc@1.1.3/sharejs/dist/js/social-share.min.js" defer></script></div></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/posts/c219fcd0.html"><img class="prev-cover" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://cn.bing.com/th?id=OHR.KindredSpirits_EN-US5529252474_UHD.jpg" onerror='onerror=null,src="/img/404.jpg"' alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">七、GC 性能优化 – GC 调优(工具篇)</div></div></a></div><div class="next-post pull-right"><a href="/posts/4ae35017.html"><img class="next-cover" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://cn.bing.com/th?id=OHR.PontRouge_EN-US8216026982_UHD.jpg" onerror='onerror=null,src="/img/404.jpg"' alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">九、GC 性能优化 – 快速解读GC日志</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="anzhiyufont anzhiyu-icon-thumbs-up fa-fw" style="font-size:1.5rem;margin-right:4px"></i><span>喜欢这篇文章的人也看了</span></div><div class="relatedPosts-list"><div><a href="/posts/c219fcd0.html" title="七、GC 性能优化 – GC 调优(工具篇)"><img class="cover" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://cn.bing.com/th?id=OHR.KindredSpirits_EN-US5529252474_UHD.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="anzhiyufont anzhiyu-icon-calendar-days fa-fw"></i> 2019-01-30</div><div class="title">七、GC 性能优化 – GC 调优(工具篇)</div></div></a></div><div><a href="/posts/1cbf2ab0.html" title="六、GC 性能优化 – GC 调优(基础篇)"><img class="cover" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://cn.bing.com/th?id=OHR.MistyForest_EN-US5261676101_UHD.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="anzhiyufont anzhiyu-icon-calendar-days fa-fw"></i> 2019-01-29</div><div class="title">六、GC 性能优化 – GC 调优(基础篇)</div></div></a></div><div><a href="/posts/46b81885.html" title="五、GC 性能优化 – GC 算法(实现篇)"><img class="cover" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://cn.bing.com/th?id=OHR.Dargavs_EN-US4957085337_UHD.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="anzhiyufont anzhiyu-icon-calendar-days fa-fw"></i> 2019-01-28</div><div class="title">五、GC 性能优化 – GC 算法(实现篇)</div></div></a></div><div><a href="/posts/a63b36e1.html" title="四、GC 性能优化 – GC 算法(基础篇)"><img class="cover" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://cn.bing.com/th?id=OHR.RedFoxBlackForest_EN-US4823848176_UHD.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="anzhiyufont anzhiyu-icon-calendar-days fa-fw"></i> 2019-01-27</div><div class="title">四、GC 性能优化 – GC 算法(基础篇)</div></div></a></div><div><a href="/posts/2711940d0c.html" title="三、GC 性能优化 – Java中的垃圾收集"><img class="cover" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://cn.bing.com/th?id=OHR.Bavljenac_EN-US8692148480_UHD.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="anzhiyufont anzhiyu-icon-calendar-days fa-fw"></i> 2019-01-26</div><div class="title">三、GC 性能优化 – Java中的垃圾收集</div></div></a></div><div><a href="/posts/fb861b08.html" title="二、GC 性能优化 – 垃圾收集简介"><img class="cover" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://cn.bing.com/th?id=OHR.Neowise_EN-US4428390515_UHD.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="anzhiyufont anzhiyu-icon-calendar-days fa-fw"></i> 2019-01-25</div><div class="title">二、GC 性能优化 – 垃圾收集简介</div></div></a></div></div></div><hr><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="anzhiyufont anzhiyu-icon-comments"></i><span> 评论</span></div><div class="comment-randomInfo"><a onclick="anzhiyu.addRandomCommentInfo()" href="javascript:void(0)" rel="external nofollow noreferrer">匿名评论</a><a href="/privacy" style="margin-left:4px">隐私政策</a></div><div class="comment-switch"><span class="first-comment">Twikoo</span><span id="switch-btn"></span><span class="second-comment">Artalk</span></div><div class="comment-tips" id="comment-tips"><span>✅ 你无需删除空行，直接评论以获取最佳展示效果</span></div></div><div class="comment-wrap"><div><div id="twikoo-wrap"></div></div><div><div id="artalk-wrap"></div></div></div></div><div class="comment-barrage"></div></div><div class="aside-content" id="aside-content"><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="anzhiyufont anzhiyu-icon-bars"></i><span>文章目录</span><span class="toc-percentage"></span></div><div class="toc-content is-expand"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%85%AB%E3%80%81GC-%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96-%E2%80%93-GC-%E8%B0%83%E4%BC%98-%E5%AE%9E%E6%88%98%E7%AF%87"><span class="toc-number">1.</span> <span class="toc-text">八、GC 性能优化 – GC 调优(实战篇)</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%AB%98%E5%88%86%E9%85%8D%E9%80%9F%E7%8E%87-High-Allocation-Rate"><span class="toc-number">1.1.</span> <span class="toc-text">高分配速率(High Allocation Rate)</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A6%82%E4%BD%95%E6%B5%8B%E9%87%8F%E5%88%86%E9%85%8D%E9%80%9F%E7%8E%87"><span class="toc-number">1.1.1.</span> <span class="toc-text">如何测量分配速率?</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%86%E9%85%8D%E9%80%9F%E7%8E%87%E7%9A%84%E6%84%8F%E4%B9%89"><span class="toc-number">1.1.2.</span> <span class="toc-text">分配速率的意义</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%A4%BA%E4%BE%8B"><span class="toc-number">1.1.3.</span> <span class="toc-text">示例</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%AB%98%E5%88%86%E9%85%8D%E9%80%9F%E7%8E%87%E5%AF%B9JVM%E7%9A%84%E5%BD%B1%E5%93%8D"><span class="toc-number">1.1.4.</span> <span class="toc-text">高分配速率对JVM的影响</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88"><span class="toc-number">1.1.5.</span> <span class="toc-text">解决方案</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%BF%87%E6%97%A9%E6%8F%90%E5%8D%87-Premature-Promotion"><span class="toc-number">1.2.</span> <span class="toc-text">过早提升(Premature Promotion)</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A6%82%E4%BD%95%E6%B5%8B%E9%87%8F%E6%8F%90%E5%8D%87%E9%80%9F%E7%8E%87"><span class="toc-number">1.2.1.</span> <span class="toc-text">如何测量提升速率</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%8F%90%E5%8D%87%E9%80%9F%E7%8E%87%E7%9A%84%E6%84%8F%E4%B9%89"><span class="toc-number">1.2.2.</span> <span class="toc-text">提升速率的意义</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%A4%BA%E4%BE%8B-1"><span class="toc-number">1.2.3.</span> <span class="toc-text">示例</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%BF%87%E6%97%A9%E6%8F%90%E5%8D%87%E7%9A%84%E5%BD%B1%E5%93%8D"><span class="toc-number">1.2.4.</span> <span class="toc-text">过早提升的影响</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88-1"><span class="toc-number">1.2.5.</span> <span class="toc-text">解决方案</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Weak-Soft-%E5%8F%8A-Phantom-%E5%BC%95%E7%94%A8"><span class="toc-number">1.3.</span> <span class="toc-text">Weak, Soft 及 Phantom 引用</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BC%B1%E5%BC%95%E7%94%A8%E7%9A%84%E7%BC%BA%E7%82%B9"><span class="toc-number">1.4.</span> <span class="toc-text">弱引用的缺点</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%A4%BA%E4%BE%8B-2"><span class="toc-number">1.5.</span> <span class="toc-text">示例</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8%E9%9D%9E%E5%BC%BA%E5%BC%95%E7%94%A8%E7%9A%84%E5%BD%B1%E5%93%8D"><span class="toc-number">1.5.1.</span> <span class="toc-text">使用非强引用的影响</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88-2"><span class="toc-number">1.5.2.</span> <span class="toc-text">解决方案</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%B6%E4%BB%96%E7%A4%BA%E4%BE%8B"><span class="toc-number">1.6.</span> <span class="toc-text">其他示例</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#RMI-%E4%B8%8E-GC"><span class="toc-number">1.6.1.</span> <span class="toc-text">RMI 与 GC</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JVMTI-tagging-%E4%B8%8E-GC"><span class="toc-number">1.6.2.</span> <span class="toc-text">JVMTI tagging 与 GC</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%B7%A8%E6%97%A0%E9%9C%B8%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%86%E9%85%8D-Humongous-Allocations"><span class="toc-number">1.6.3.</span> <span class="toc-text">巨无霸对象的分配(Humongous Allocations)</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-number">1.6.4.</span> <span class="toc-text">总结</span></a></li></ol></li></ol></li></ol></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div id="footer_deal"><a class="deal_link" href="mailto:2071916845@qq.com" rel="external nofollow noreferrer" title="email"><i class="anzhiyufont anzhiyu-icon-envelope"></i></a><a class="deal_link" target="_blank" rel="noopener external nofollow noreferrer" href="https://weibo.com/" title="微博"><i class="anzhiyufont anzhiyu-icon-weibo"></i></a><a class="deal_link" target="_blank" rel="noopener external nofollow noreferrer" href="https://www.facebook.com/" title="facebook"><i class="anzhiyufont anzhiyu-icon-facebook1"></i></a><a class="deal_link" href="/atom.xml" title="RSS"><i class="anzhiyufont anzhiyu-icon-rss"></i></a><img class="footer_mini_logo" title="返回顶部" alt="返回顶部" onclick="anzhiyu.scrollToDest(0,500)" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://q1.qlogo.cn/g?b=qq&amp;nk=2071916845&amp;s=640" size="50px"><a class="deal_link" target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/it985" title="Github"><i class="anzhiyufont anzhiyu-icon-github"></i></a><a class="deal_link" target="_blank" rel="noopener external nofollow noreferrer" href="https://space.bilibili.com/300767383" title="Bilibili"><i class="anzhiyufont anzhiyu-icon-bilibili"></i></a><a class="deal_link" target="_blank" rel="noopener external nofollow noreferrer" href="https://v.douyin.com/" title="抖音"><i class="anzhiyufont anzhiyu-icon-tiktok"></i></a><a class="deal_link" href="/copyright" title="CC"><i class="anzhiyufont anzhiyu-icon-copyright-line"></i></a></div><div id="anzhiyu-footer"><div class="footer-group"><div class="footer-title">服务</div><div class="footer-links"><a class="footer-item" title="51la统计" target="_blank" rel="noopener external nofollow noreferrer" href="https://v6.51.la/">51la统计</a><a class="footer-item" title="十年之约" target="_blank" rel="noopener external nofollow noreferrer" href="https://www.foreverblog.cn/">十年之约</a><a class="footer-item" title="开往" target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/travellings-link/travellings">开往</a></div></div><div class="footer-group"><div class="footer-title">导航</div><div class="footer-links"><a class="footer-item" title="即刻短文" href="/essay/">即刻短文</a><a class="footer-item" title="友链文章" href="/fcircle/">友链文章</a><a class="footer-item" title="留言板" href="/comments/">留言板</a></div></div><div class="footer-group"><div class="footer-title">协议</div><div class="footer-links"><a class="footer-item" title="免责声明" href="/disclaimer/">免责声明</a><a class="footer-item" title="隐私协议" href="/privacy/">隐私协议</a><a class="footer-item" title="Cookies" href="/cookies/">Cookies</a><a class="footer-item" title="版权协议" href="/copyright/">版权协议</a></div></div><div class="footer-group"><div class="footer-title">娱乐</div><div class="footer-links"><a class="footer-item" title="小空调" href="/air-conditioner/">小空调</a><a class="footer-item" title="围住小猫" href="/catch-cat/">围住小猫</a><a class="footer-item" title="免费图床" href="/huluxiapicture/">免费图床</a></div></div><div class="footer-group"><div class="footer-title">推荐分类</div><div class="footer-links"><a class="footer-item" title="Java" href="/categories/Java/">Java</a><a class="footer-item" title="面试" href="/categories/%E9%9D%A2%E8%AF%95/">面试</a></div></div><div class="footer-group"><div class="footer-title-group"><div class="footer-title">友链</div><a class="random-friends-btn" id="footer-random-friends-btn" href="javascript:addFriendLinksInFooter();" rel="external nofollow noreferrer" title="换一批友情链接"><i class="anzhiyufont anzhiyu-icon-arrow-rotate-right"></i></a></div><div class="footer-links" id="friend-links-in-footer"></div></div></div><div id="workboard"><img class="workSituationImg boardsign" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://npm.elemecdn.com/anzhiyu-blog@2.0.4/img/badge/安知鱼-上班摸鱼中.svg" alt="距离月入25k也就还差一个大佬带我~" title="距离月入25k也就还差一个大佬带我~"><div id="runtimeTextTip"></div></div><div class="wordcount"></div><span>云少已经写了 996.7k 字，</span><span>好像写完一本我国著名的 四大名著 了！！！</span><p id="ghbdages"><a class="github-badge" target="_blank" href="https://hexo.io/" rel="external nofollow noreferrer" style="margin-inline:5px" data-title="博客框架为Hexo_v5.4.0" title="博客框架为Hexo_v5.4.0"><img src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://npm.elemecdn.com/anzhiyu-blog@2.1.5/img/badge/Frame-Hexo.svg" alt="博客框架为Hexo_v5.4.0"></a><a class="github-badge" target="_blank" href="https://www.upyun.com/?utm_source=lianmeng&amp;utm_medium=referral" rel="external nofollow noreferrer" style="margin-inline:5px" data-title="本站使用又拍云为静态资源提供CDN加速" title="本站使用又拍云为静态资源提供CDN加速"><img src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://img.shields.io/badge/CDN-%E5%8F%88%E6%8B%8D%E4%BA%91-orange%3Fstyle%3Dflat%26logo%3D%E5%8F%88%E6%8B%8D%E4%BA%91" alt="本站使用又拍云为静态资源提供CDN加速"></a><a class="github-badge" target="_blank" href="https://github.com/" rel="external nofollow noreferrer" style="margin-inline:5px" data-title="本站项目由Github托管" title="本站项目由Github托管"><img src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://npm.elemecdn.com/anzhiyu-blog@2.1.5/img/badge/Source-Github.svg" alt="本站项目由Github托管"></a><a class="github-badge" target="_blank" href="http://creativecommons.org/licenses/by-nc-sa/4.0/" rel="external nofollow noreferrer" style="margin-inline:5px" data-title="本站采用知识共享署名-非商业性使用-相同方式共享4.0国际许可协议进行许可" title="本站采用知识共享署名-非商业性使用-相同方式共享4.0国际许可协议进行许可"><img src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://npm.elemecdn.com/anzhiyu-blog@2.2.0/img/badge/Copyright-BY-NC-SA.svg" alt="本站采用知识共享署名-非商业性使用-相同方式共享4.0国际许可协议进行许可"></a><a class="github-badge" target="_blank" href="https://icp.gov.moe/?keyword=20221607" rel="external nofollow noreferrer" style="margin-inline:5px" data-title="萌ICP备20221607号" title="萌ICP备20221607号"><img src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://img.shields.io/badge/%E8%90%8CICP%E5%A4%87-20221607-fe1384?style-flat&amp;logo=" alt="萌ICP备20221607号"></a></p></div><div id="footer-bar"><div class="footer-bar-links"><div class="footer-bar-left"><div id="footer-bar-tips"><div class="copyright">&copy;2018 - 2023 By <a class="footer-bar-link" href="/" title="云少" target="_blank">云少</a></div></div><div id="footer-type-tips"></div><div class="js-pjax"><script>function subtitleType(){fetch("https://v1.hitokoto.cn").then(t=>t.json()).then(t=>{var e="出自 "+t.from,p=[];p.unshift(t.hitokoto,e),window.typed=new Typed("#footer-type-tips",{strings:p,startDelay:300,typeSpeed:150,loop:!0,backSpeed:50})})}"function"==typeof Typed?subtitleType():getScript("https://cdn.cbd.int/typed.js@2.0.15/dist/typed.umd.js").then(subtitleType)</script></div></div><div class="footer-bar-right"><a class="footer-bar-link" target="_blank" rel="noopener external nofollow noreferrer" href="https://www.tryrun.top" title="云少">云少</a><a class="footer-bar-link" target="_blank" rel="noopener external nofollow noreferrer" href="https://beian.miit.gov.cn/" title="鄂ICP备2021021095号-2">鄂ICP备2021021095号-2</a><a class="footer-bar-link cc" href="/copyright" title="cc协议"><i class="anzhiyufont anzhiyu-icon-copyright-line"></i><i class="anzhiyufont anzhiyu-icon-creative-commons-by-line"></i><i class="anzhiyufont anzhiyu-icon-creative-commons-nc-line"></i><i class="anzhiyufont anzhiyu-icon-creative-commons-nd-line"></i></a></div></div></div></footer></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="sidebar-site-data site-data is-center"><a href="/archives/" title="archive"><div class="headline">文章</div><div class="length-num">861</div></a><a href="/tags/" title="tag"><div class="headline">标签</div><div class="length-num">35</div></a><a href="/categories/" title="category"><div class="headline">分类</div><div class="length-num">6</div></a></div><span class="sidebar-menu-item-title">功能</span><div class="sidebar-menu-item"><a class="darkmode_switchbutton menu-child" href="javascript:void(0);" rel="external nofollow noreferrer" title="显示模式"><i class="anzhiyufont anzhiyu-icon-circle-half-stroke"></i><span>显示模式</span></a></div><div class="back-menu-list-groups"><div class="back-menu-list-group"><div class="back-menu-list-title">网页</div><div class="back-menu-list"><a class="back-menu-item" target="_blank" rel="noopener external nofollow noreferrer" href="https://www.tryrun.top/" title="博客"><img class="back-menu-item-icon" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="/img/favicon.ico" alt="博客"><span class="back-menu-item-text">博客</span></a></div></div><div class="back-menu-list-group"><div class="back-menu-list-title">项目</div><div class="back-menu-list"><a class="back-menu-item" target="_blank" rel="noopener external nofollow noreferrer" href="https://www.tryrun.top" title="图床"><img class="back-menu-item-icon" src= "" onerror="this.onerror=null,this.src=&quot;/img/404.jpg&quot;" data-lazy-src="https://www.tryrun.top/favicon.ico" alt="图床"><span class="back-menu-item-text">图床</span></a></div></div></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="javascript:void(0);" rel="external nofollow noreferrer"><span>望四方</span></a><ul class="menus_item_child"><li><a class="site-page child faa-parent animated-hover" href="/archives/"><i class="anzhiyufont anzhiyu-icon-box-archive faa-tada" style="font-size:.9em"></i><span> 归名档</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/categories/"><i class="anzhiyufont anzhiyu-icon-shapes faa-tada" style="font-size:.9em"></i><span> 归四类</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/tags/"><i class="anzhiyufont anzhiyu-icon-tags faa-tada" style="font-size:.9em"></i><span> 书中签</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/charts/"><i class="fa-fw fas fa-chart-bar faa-tada"></i><span> 统计</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="javascript:void(0);" rel="external nofollow noreferrer"><span>友链</span></a><ul class="menus_item_child"><li><a class="site-page child faa-parent animated-hover" href="/link/"><i class="anzhiyufont anzhiyu-icon-link faa-tada" style="font-size:.9em"></i><span> 四方好友</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/fcircle/"><i class="anzhiyufont anzhiyu-icon-artstation faa-tada" style="font-size:.9em"></i><span> 朋友圈</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/comments/"><i class="anzhiyufont anzhiyu-icon-envelope faa-tada" style="font-size:.9em"></i><span> 留言板</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="javascript:void(0);" rel="external nofollow noreferrer"><span>我的</span></a><ul class="menus_item_child"><li><a class="site-page child faa-parent animated-hover" href="/bangumis/"><i class="anzhiyufont anzhiyu-icon-bilibili faa-tada" style="font-size:.9em"></i><span> 追番页</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/album/"><i class="anzhiyufont anzhiyu-icon-images faa-tada" style="font-size:.9em"></i><span> 刹那间</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/equipment/"><i class="fas fa-heart faa-tada"></i><span> 我的装备</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/collect/"><i class="fas fa-camcorder faa-tada"></i><span> 观影阁</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="javascript:void(0);" rel="external nofollow noreferrer"><span>关于</span></a><ul class="menus_item_child"><li><a class="site-page child faa-parent animated-hover" href="/about/"><i class="anzhiyufont anzhiyu-icon-paper-plane faa-tada" style="font-size:.9em"></i><span> 关于本人</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/essay/"><i class="anzhiyufont anzhiyu-icon-lightbulb faa-tada" style="font-size:.9em"></i><span> 闲言碎语</span></a></li><li><a class="site-page child faa-parent animated-hover" href="javascript:toRandomPost()" rel="external nofollow noreferrer"><i class="anzhiyufont anzhiyu-icon-shoe-prints1 faa-tada" style="font-size:.9em"></i><span> 随便逛逛</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/disclaimer/"><i class="fas fa-heart faa-tada"></i><span> 免责声明</span></a></li><li><a class="site-page child faa-parent animated-hover" href="/love/"><i class="anzhiyufont anzhiyu-icon-heartbeat faa-tada" style="font-size:.9em"></i><span> 恋爱小屋</span></a></li></ul></div></div><span class="sidebar-menu-item-title">标签</span><div class="card-tags"><div class="item-headline"></div><div class="card-tag-cloud"><a href="/tags/API/" style="font-size:.88rem;color:#758692">API<sup>43</sup></a><a href="/tags/Base64/" style="font-size:.88rem;color:#2584bf">Base64<sup>1</sup></a><a href="/tags/Collectors/" style="font-size:.88rem;color:#bfad3e">Collectors<sup>3</sup></a><a href="/tags/Date/" style="font-size:.88rem;color:#b9b609">Date<sup>3</sup></a><a href="/tags/Executor/" style="font-size:.88rem;color:#14c83c">Executor<sup>9</sup></a><a href="/tags/Guava/" style="font-size:.88rem;color:#0a1878">Guava<sup>1</sup></a><a href="/tags/JVM/" style="font-size:.88rem;color:#625421">JVM<sup>8</sup></a><a href="/tags/Java8/" style="font-size:.88rem;color:#aa71bf">Java8<sup>21</sup></a><a href="/tags/Java9/" style="font-size:.88rem;color:#ad8774">Java9<sup>21</sup></a><a href="/tags/Java%E5%B9%B6%E5%8F%91/" style="font-size:.88rem;color:#19704c">Java并发<sup>20</sup></a><a href="/tags/Lambda/" style="font-size:.88rem;color:#7e5c78">Lambda<sup>4</sup></a><a href="/tags/Lock/" style="font-size:.88rem;color:#700769">Lock<sup>1</sup></a><a href="/tags/Maven/" style="font-size:.88rem;color:#2b8671">Maven<sup>1</sup></a><a href="/tags/Memcached/" style="font-size:.88rem;color:#1b0694">Memcached<sup>23</sup></a><a href="/tags/Mongodb/" style="font-size:.88rem;color:#36202d">Mongodb<sup>49</sup></a><a href="/tags/Queue/" style="font-size:.88rem;color:#643f76">Queue<sup>1</sup></a><a href="/tags/Redis/" style="font-size:.88rem;color:#1e4c38">Redis<sup>27</sup></a><a href="/tags/Stream/" style="font-size:.88rem;color:#a5a097">Stream<sup>4</sup></a><a href="/tags/Thread/" style="font-size:.88rem;color:#05682d">Thread<sup>7</sup></a><a href="/tags/Thread-pool/" style="font-size:.88rem;color:#38ad2a">Thread pool<sup>7</sup></a><a href="/tags/forkJoinPool/" style="font-size:.88rem;color:#827a6b">forkJoinPool<sup>2</sup></a><a href="/tags/stream/" style="font-size:.88rem;color:#4a3ac7">stream<sup>1</sup></a><a href="/tags/%E4%B8%93%E6%A0%8F/" style="font-size:.88rem;color:#b89c14">专栏<sup>35</sup></a><a href="/tags/%E4%BA%8B%E5%8A%A1/" style="font-size:.88rem;color:#922401">事务<sup>1</sup></a><a href="/tags/%E4%BC%98%E5%8C%96/" style="font-size:.88rem;color:#437d09">优化<sup>1</sup></a><a href="/tags/%E5%91%BD%E4%BB%A4/" style="font-size:.88rem;color:#705b06">命令<sup>57</sup></a><a href="/tags/%E5%AE%89%E8%A3%85/" style="font-size:.88rem;color:#06a544">安装<sup>6</sup></a><a href="/tags/%E5%B7%A5%E5%85%B7/" style="font-size:.88rem;color:#c86c4f">工具<sup>2</sup></a><a href="/tags/%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/" style="font-size:.88rem;color:#560b2c">数据类型<sup>8</sup></a><a href="/tags/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/" style="font-size:.88rem;color:#4e0a32">生命周期<sup>1</sup></a><a href="/tags/%E7%AE%80%E4%BB%8B/" style="font-size:.88rem;color:#230f8e">简介<sup>7</sup></a><a href="/tags/%E7%AE%97%E6%B3%95/" style="font-size:.88rem;color:#c0771e">算法<sup>10</sup></a><a href="/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" style="font-size:.88rem;color:#b40caa">设计模式<sup>38</sup></a><a href="/tags/%E9%85%8D%E7%BD%AE/" style="font-size:.88rem;color:#67389a">配置<sup>2</sup></a><a href="/tags/%E9%9D%A2%E8%AF%95/" style="font-size:.88rem;color:#57425c">面试<sup>11</sup></a></div></div><hr></div></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="anzhiyufont anzhiyu-icon-book-open"></i></button><button id="translateLink" type="button" title="简繁转换">繁</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="anzhiyufont anzhiyu-icon-circle-half-stroke"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="anzhiyufont anzhiyu-icon-arrows-left-right"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="anzhiyufont anzhiyu-icon-gear"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="anzhiyufont anzhiyu-icon-list-ul"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="anzhiyufont anzhiyu-icon-comments"></i></a><button type="button" title="切换背景" onclick="toggleWinbox()"><i class="fas fa-display"></i></button><button id="go-up" type="button" title="回到顶部"><i class="anzhiyufont anzhiyu-icon-arrow-up"></i></button></div></div><div id="algolia-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><button class="search-close-button"><i class="anzhiyufont anzhiyu-icon-xmark"></i></button></nav><div class="search-wrap"><div id="algolia-search-input"></div><hr><div id="algolia-search-results"><div id="algolia-hits"></div><div id="algolia-pagination"></div><div id="algolia-info"><div class="algolia-stats"></div><div class="algolia-poweredBy"></div></div></div></div></div><div id="search-mask"></div></div><div id="rightMenu"><div class="rightMenu-group rightMenu-small"><div class="rightMenu-item" id="menu-backward"><i class="anzhiyufont anzhiyu-icon-arrow-left"></i></div><div class="rightMenu-item" id="menu-forward"><i class="anzhiyufont anzhiyu-icon-arrow-right"></i></div><div class="rightMenu-item" id="menu-refresh"><i class="anzhiyufont anzhiyu-icon-arrow-rotate-right" style="font-size:1rem"></i></div><div class="rightMenu-item" id="menu-top"><i class="anzhiyufont anzhiyu-icon-arrow-up"></i></div></div><div class="rightMenu-group rightMenu-line rightMenuPlugin"><div class="rightMenu-item" id="menu-copytext"><i class="anzhiyufont anzhiyu-icon-copy"></i><span>复制选中文本</span></div><div class="rightMenu-item" id="menu-pastetext"><i class="anzhiyufont anzhiyu-icon-paste"></i><span>粘贴文本</span></div><a class="rightMenu-item" id="menu-commenttext"><i class="anzhiyufont anzhiyu-icon-comment-medical"></i><span>引用到评论</span></a><div class="rightMenu-item" id="menu-newwindow"><i class="anzhiyufont anzhiyu-icon-window-restore"></i><span>新窗口打开</span></div><div class="rightMenu-item" id="menu-copylink"><i class="anzhiyufont anzhiyu-icon-link"></i><span>复制链接地址</span></div><div class="rightMenu-item" id="menu-copyimg"><i class="anzhiyufont anzhiyu-icon-images"></i><span>复制此图片</span></div><div class="rightMenu-item" id="menu-downloadimg"><i class="anzhiyufont anzhiyu-icon-download"></i><span>下载此图片</span></div><div class="rightMenu-item" id="menu-newwindowimg"><i class="anzhiyufont anzhiyu-icon-window-restore"></i><span>新窗口打开图片</span></div><div class="rightMenu-item" id="menu-search"><i class="anzhiyufont anzhiyu-icon-magnifying-glass"></i><span>站内搜索</span></div><div class="rightMenu-item" id="menu-searchBaidu"><i class="anzhiyufont anzhiyu-icon-magnifying-glass"></i><span>百度搜索</span></div><div class="rightMenu-item" id="menu-music-toggle"><i class="anzhiyufont anzhiyu-icon-play"></i><span>播放音乐</span></div><div class="rightMenu-item" id="menu-music-back"><i class="anzhiyufont anzhiyu-icon-backward"></i><span>切换到上一首</span></div><div class="rightMenu-item" id="menu-music-forward"><i class="anzhiyufont anzhiyu-icon-forward"></i><span>切换到下一首</span></div><div class="rightMenu-item" id="menu-music-playlist" onclick="window.open(&quot;https://y.qq.com/n/ryqq/playlist/8802438608&quot;, &quot;_blank&quot;);" style="display:none"><i class="anzhiyufont anzhiyu-icon-radio"></i><span>查看所有歌曲</span></div><div class="rightMenu-item" id="menu-music-copyMusicName"><i class="anzhiyufont anzhiyu-icon-copy"></i><span>复制歌名</span></div></div><div class="rightMenu-group rightMenu-line rightMenuOther"><a class="rightMenu-item menu-link" id="menu-randomPost"><i class="anzhiyufont anzhiyu-icon-shuffle"></i><span>随便逛逛</span></a><a class="rightMenu-item menu-link" href="/categories/"><i class="anzhiyufont anzhiyu-icon-cube"></i><span>博客分类</span></a><a class="rightMenu-item menu-link" href="/tags/"><i class="anzhiyufont anzhiyu-icon-tags"></i><span>文章标签</span></a></div><div class="rightMenu-group rightMenu-line rightMenuOther"><a class="rightMenu-item" id="menu-copy" href="javascript:void(0);" rel="external nofollow noreferrer"><i class="anzhiyufont anzhiyu-icon-copy"></i><span>复制地址</span></a><a class="rightMenu-item" id="menu-commentBarrage" href="javascript:void(0);" rel="external nofollow noreferrer"><i class="anzhiyufont anzhiyu-icon-message"></i><span class="menu-commentBarrage-text">关闭热评</span></a><a class="rightMenu-item" id="menu-darkmode" href="javascript:void(0);" rel="external nofollow noreferrer"><i class="anzhiyufont anzhiyu-icon-circle-half-stroke"></i><span class="menu-darkmode-text">深色模式</span></a><a class="rightMenu-item" id="menu-translate" href="javascript:void(0);" rel="external nofollow noreferrer"><i class="anzhiyufont anzhiyu-icon-language"></i><span>轉為繁體</span></a></div></div><div id="rightmenu-mask"></div><div id="he-plugin-simple"></div><script>var WIDGET={CONFIG:{modules:"0124",background:"2",tmpColor:"FFFFFF",tmpSize:"16",cityColor:"FFFFFF",citySize:"16",aqiColor:"E8D87B",aqiSize:"16",weatherIconSize:"24",alertIconSize:"18",padding:"10px 10px 10px 10px",shadow:"0",language:"auto",borderRadius:"20",fixed:"true",vertical:"top",horizontal:"left",left:"20",top:"7.1",key:"df245676fb434a0691ead1c63341cd94"}}</script><link rel="stylesheet" href="https://widget.qweather.net/simple/static/css/he-simple.css?v=1.4.0"><script src="https://widget.qweather.net/simple/static/js/he-simple.js?v=1.4.0"></script><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><script src="https://cdn.cbd.int/@fancyapps/ui@5.0.20/dist/fancybox/fancybox.umd.js"></script><script src="https://cdn.cbd.int/instant.page@5.2.0/instantpage.js" type="module"></script><script src="https://cdn.cbd.int/vanilla-lazyload@17.8.4/dist/lazyload.iife.min.js"></script><script src="https://cdn.cbd.int/node-snackbar@0.1.16/dist/snackbar.min.js"></script><script>function panguFn(){"object"==typeof pangu?pangu.autoSpacingPage():getScript("https://cdn.cbd.int/pangu@4.0.7/dist/browser/pangu.min.js").then(()=>{pangu.autoSpacingPage()})}function panguInit(){panguFn()}document.addEventListener("DOMContentLoaded",panguInit)</script><script>var meting_api="https://api.injahow.cn/meting/?server=:server&type=:type&id=:id&auth=:auth&r=:r"</script><canvas id="universe"></canvas><script async src="https://npm.elemecdn.com/anzhiyu-theme-static@1.0.0/dark/dark.js"></script><script>var HoldLog=console.log;console.log=function(){};let now1=new Date;queueMicrotask(()=>{function o(){HoldLog.apply(console,arguments)}var c=new Date("09/01/2018 00:00:00"),c=(now1.setTime(now1.getTime()+250),(now1-c)/1e3/60/60/24),c=["欢迎使用安知鱼!","生活明朗, 万物可爱",`
        
       █████╗ ███╗   ██╗███████╗██╗  ██╗██╗██╗   ██╗██╗   ██╗
      ██╔══██╗████╗  ██║╚══███╔╝██║  ██║██║╚██╗ ██╔╝██║   ██║
      ███████║██╔██╗ ██║  ███╔╝ ███████║██║ ╚████╔╝ ██║   ██║
      ██╔══██║██║╚██╗██║ ███╔╝  ██╔══██║██║  ╚██╔╝  ██║   ██║
      ██║  ██║██║ ╚████║███████╗██║  ██║██║   ██║   ╚██████╔╝
      ╚═╝  ╚═╝╚═╝  ╚═══╝╚══════╝╚═╝  ╚═╝╚═╝   ╚═╝    ╚═════╝
        
        `,"已上线",Math.floor(c),"天","©2018 By 安知鱼 V1.6.6"],e=["NCC2-036","调用前置摄像头拍照成功，识别为【小笨蛋】.","Photo captured: ","🤪"];setTimeout(o.bind(console,`
%c${c[0]} %c ${c[1]} %c ${c[2]} %c${c[3]}%c ${c[4]}%c ${c[5]}

%c ${c[6]}
`,"color:#425AEF","","color:#425AEF","color:#425AEF","","color:#425AEF","")),setTimeout(o.bind(console,`%c ${e[0]} %c ${e[1]} %c 
${e[2]} %c
${e[3]}
`,"color:white; background-color:#4fd953","","",'background:url("https://npm.elemecdn.com/anzhiyu-blog@1.1.6/img/post/common/tinggge.gif") no-repeat;font-size:450%')),setTimeout(o.bind(console,"%c WELCOME %c 你好，小笨蛋.","color:white; background-color:#4f90d9","")),setTimeout(console.warn.bind(console,"%c ⚡ Powered by 安知鱼 %c 你正在访问 云少 的博客.","color:white; background-color:#f0ad4e","")),setTimeout(o.bind(console,"%c W23-12 %c 你已打开控制台.","color:white; background-color:#4f90d9","")),setTimeout(console.warn.bind(console,"%c S013-782 %c 你现在正处于监控中.","color:white; background-color:#d9534f",""))})</script><script async src="/anzhiyu/random.js"></script><script async>!function(){var n,o,r,a,i,e=new Date("09/01/2018 00:00:00"),l=new Date;setInterval(()=>{var t;if(l=new Date,i=l.getHours(),t=(l-e)/1e3/60/60/24,n=Math.floor(t),t=(l-e)/1e3/60/60-24*n,o=Math.floor(t),1==String(o).length&&(o="0"+o),t=(l-e)/1e3/60-1440*n-60*o,r=Math.floor(t),1==String(r).length&&(r="0"+r),t=(l-e)/1e3-86400*n-3600*o-60*r,a=Math.round(t),1==String(a).length&&(a="0"+a),document.getElementById("footer")){let e="";e=(i<18&&9<=i||((t=document.querySelector("#workboard .workSituationImg")).src="https://npm.elemecdn.com/anzhiyu-blog@2.0.4/img/badge/安知鱼-下班啦.svg",t.title="下班了就该开开心心的玩耍，嘿嘿~",t.alt="下班了就该开开心心的玩耍，嘿嘿~"),`本站居然运行了 ${n} 天<span id='runtime'> ${o} 小时 ${r} 分 ${a} 秒 </span><i class='anzhiyufont anzhiyu-icon-heartbeat' style='color:red'></i>`),document.getElementById("runtimeTextTip")&&(document.getElementById("runtimeTextTip").innerHTML=e)}},1e3)}()</script><script src="https://cdn.cbd.int/algoliasearch@4.18.0/dist/algoliasearch-lite.umd.js"></script><script src="https://cdn.cbd.int/instantsearch.js@4.56.5/dist/instantsearch.production.min.js"></script><script src="/js/search/algolia.js"></script><div class="js-pjax"><script>(()=>{const e=document.querySelectorAll("#article-container .mermaid-wrap");if(0!==e.length){const n=()=>{window.loadMermaid=!0;const a="dark"===document.documentElement.getAttribute("data-theme")?"dark":"default";Array.from(e).forEach((e,t)=>{const n=e.firstElementChild;e="%%{init:{ 'theme':'"+a+"'}}%%\n"+n.textContent;const d=mermaid.render("mermaid-"+t,e);"string"==typeof d?(t=d,n.insertAdjacentHTML("afterend",t)):d.then(({svg:e})=>{n.insertAdjacentHTML("afterend",e)})})};var t=()=>{window.loadMermaid?n():getScript("https://cdn.cbd.int/mermaid@10.2.4/dist/mermaid.min.js").then(n)};anzhiyu.addGlobalFn("themeChange",n,"mermaid"),window.pjax?t():document.addEventListener("DOMContentLoaded",t)}})()</script><script>(()=>{const t=()=>{twikoo.init(Object.assign({el:"#twikoo-wrap",envId:"https://twikoo.tryrun.top/",region:"",onCommentLoaded:()=>{anzhiyu.loadLightbox(document.querySelectorAll("#twikoo .tk-content img:not(.tk-owo-emotion)"))}},null))};var o=()=>{"object"==typeof twikoo?setTimeout(n,0):getScript("https://cdn.cbd.int/twikoo@1.6.18/dist/twikoo.all.min.js").then(n)};const n=()=>{t()};anzhiyu.loadComment(document.getElementById("twikoo-wrap"),o)})()</script><script>(()=>{const t=()=>{window.artalkItem=new Artalk(Object.assign({el:"#artalk-wrap",server:"https://artalk.tryrun.top/",site:"https://blog.tryrun.top/",pageKey:location.pathname,darkMode:"dark"===document.documentElement.getAttribute("data-theme"),countEl:".artalk-count"},null)),"null"!==GLOBAL_CONFIG.lightbox&&window.artalkItem.use(t=>{t.on("list-loaded",()=>{t.getCommentList().forEach(t=>{t=t.getRender().$content;anzhiyu.loadLightbox(t.querySelectorAll("img:not([atk-emoticon])"))})})})};var a=async()=>{"object"==typeof window.artalkItem||(await getCSS("https://cdn.cbd.int/artalk@2.5.5/dist/Artalk.css"),await getScript("https://cdn.cbd.int/artalk@2.5.5/dist/Artalk.js")),t()};anzhiyu.addGlobalFn("themeChange",t=>{var a=document.getElementById("artalk-wrap");a&&a.children.length&&window.artalkItem.setDarkMode("dark"===t)},"artalk"),window.loadOtherComment=a})()</script><input type="hidden" name="page-type" id="page-type" value="post"></div><script>window.addEventListener("load",()=>{const t=e=>e=""!==e&&150<(e=(e=(e=(e=e.replace(/<img.*?src="(.*?)"?[^\>]+>/gi,"[图片]")).replace(/<a[^>]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi,"[链接]")).replace(/<pre><code>.*?<\/pre>/gi,"[代码]")).replace(/<[^>]+>/g,"")).length?e.substring(0,150)+"...":e,n=t=>{let n="";if(t.length)for(let e=0;e<t.length;e++)n=(n=(n+="<div class='aside-list-item'>")+`<a href='${t[e].url}' class='thumbnail'><img data-lazy-src='${t[e].avatar}' alt='${t[e].nick}'><div class='name'><span>${t[e].nick} </span></div></a>`)+`<div class='content'>
        <a class='comment' href='${t[e].url}' title='${t[e].content}'>${t[e].content}</a>
        <time datetime="${t[e].date}">${anzhiyu.diffDate(t[e].date,!0)}</time></div>
        </div>`;else n+="没有评论";var e=document.querySelector("#card-newest-comments .aside-list");e.innerHTML=n,window.lazyLoadInstance&&window.lazyLoadInstance.update(),window.pjax&&window.pjax.refresh(e)};var e=()=>{var e;document.querySelector("#card-newest-comments .aside-list")&&((e=saveToLocal.get("twikoo-newest-comments"))?n(JSON.parse(e)):(e=()=>{twikoo.getRecentComments({envId:"https://twikoo.tryrun.top/",region:"",pageSize:6,includeReply:!0}).then(function(e){e=e.map(e=>({content:t(e.comment),avatar:e.avatar,nick:e.nick,url:e.url+"#"+e.id,date:new Date(e.created).toISOString()}));saveToLocal.set("twikoo-newest-comments",JSON.stringify(e),10/1440),n(e)}).catch(function(e){document.querySelector("#card-newest-comments .aside-list").textContent="无法获取评论，请确认相关配置是否正确"})},"object"==typeof twikoo?e():getScript("https://cdn.cbd.int/twikoo@1.6.18/dist/twikoo.all.min.js").then(e)))};e(),document.addEventListener("pjax:complete",e)})</script><script async data-pjax src="https://npm.elemecdn.com/anzhiyu-theme-static@1.0.1/bubble/bubble.js"></script><script>var visitorMail="visitor@anheyu.com"</script><script async data-pjax src="https://cdn.cbd.int/anzhiyu-theme-static@1.0.0/waterfall/waterfall.js"></script><script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/qrcodejs/1.0.0/qrcode.min.js"></script><script src="/js/anzhiyu/right_click_menu.js"></script><link rel="stylesheet" href="https://cdn.cbd.int/anzhiyu-theme-static@1.1.9/icon/ali_iconfont_css.css"><script async src="/js/1.min.js?1"></script><script async src="/js/bg.js?1"></script><script async src="https://cdn1.tianli0.top/npm/sweetalert2@8.19.0/dist/sweetalert2.all.js"></script><script async src="/js/lunar.min.js?1"></script><script async src="/js/day.min.js?1"></script><script async src="/js/winbox.bundle.min.js?1"></script><script id="click-show-text" src="https://cdn.cbd.int/butterfly-extsrc@1.1.3/dist/click-show-text.min.js" data-mobile="true" data-text="富强,民主,文明,和谐,自由,平等,公正,法治,爱国,敬业,诚信,友善" data-fontsize="15px" data-random="true" async></script><link rel="stylesheet" href="https://cdn.cbd.int/anzhiyu-theme-static@1.0.0/aplayer/APlayer.min.css" media="print" onload='this.media="all"'><script src="https://cdn.cbd.int/anzhiyu-blog-static@1.0.1/js/APlayer.min.js"></script><script src="https://cdn.cbd.int/hexo-anzhiyu-music@1.0.1/assets/js/Meting2.min.js"></script><script src="https://cdn.cbd.int/pjax@0.2.8/pjax.min.js"></script><script>let pjaxSelectors=['meta[property="og:image"]','meta[property="og:title"]','meta[property="og:url"]','meta[property="og:type"]','meta[property="og:site_name"]','meta[property="og:description"]',"head > title","#config-diff","#body-wrap","#rightside-config-hide","#rightside-config-show",".js-pjax"];var pjax=new Pjax({elements:'a:not([target="_blank"])',selectors:pjaxSelectors,cacheBust:!1,analytics:!0,scrollRestoration:!1});document.addEventListener("pjax:send",function(){if(anzhiyu.removeGlobalFnEvent("pjax"),anzhiyu.removeGlobalFnEvent("themeChange"),document.getElementById("rightside").classList.remove("rightside-show"),window.aplayers)for(let e=0;e<window.aplayers.length;e++)window.aplayers[e].options.fixed||window.aplayers[e].destroy();"object"==typeof typed&&typed.destroy();var e=document.body.classList;e.contains("read-mode")&&e.remove("read-mode")}),document.addEventListener("pjax:complete",function(){window.refreshFn(),document.querySelectorAll("script[data-pjax]").forEach(e=>{const t=document.createElement("script");var a=e.text||e.textContent||e.innerHTML||"";Array.from(e.attributes).forEach(e=>t.setAttribute(e.name,e.value)),t.appendChild(document.createTextNode(a)),e.parentNode.replaceChild(t,e)}),GLOBAL_CONFIG.islazyload&&window.lazyLoadInstance.update(),"function"==typeof chatBtnFn&&chatBtnFn(),"function"==typeof panguInit&&panguInit(),"function"==typeof gtag&&gtag("config","G-3VMKW5TZBM",{page_path:window.location.pathname}),"object"==typeof _hmt&&_hmt.push(["_trackPageview",window.location.pathname]),"function"==typeof loadMeting&&document.getElementsByClassName("aplayer").length&&loadMeting(),"object"==typeof Prism&&Prism.highlightAll()}),document.addEventListener("pjax:error",e=>{404===e.request.status&&pjax.loadUrl("/404.html")})</script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><script charset="UTF-8" src="https://cdn.cbd.int/anzhiyu-theme-static@1.1.5/accesskey/accesskey.js"></script></div><div id="popup-window"><div class="popup-window-title">通知</div><div class="popup-window-divider"></div><div class="popup-window-content"><div class="popup-tip">你好呀</div><div class="popup-link"><i class="anzhiyufont anzhiyu-icon-arrow-circle-right"></i></div></div></div></body></html>